我正在写一个应用程序,它应该将一堆文件从一个地方复制到另一个地方。
当我使用TFileStream进行复制时,比使用操作系统复制文件要慢3-4倍。
当我使用TFileStream进行复制时,比使用操作系统复制文件要慢3-4倍。
我也试图用缓冲区复制,但是也太慢了。@H_403_4@
我正在Win32工作,任何人都有这方面的见解?@H_403_4@
解决方法@H_403_9@
有几个选择。
>你可以调用使用的CopyFile
CopyFileA windows API@H_403_4@
>你可以调用浏览器使用的api(windows api
SHFileOperation)。一个例子
调用该函数可以找到
SCIP.be
>你可以编写自己的使用缓冲区的函数。@H_403_4@
如果您知道要复制的文件类型,则第3种方法通常会胜过其他方式。因为Windows API更适合整体最佳情况(小文件,大文件,网络上的文件,慢驱动器上的文件)。您可以根据需要调整自己的复印功能。@H_403_4@
以下是我自己的缓冲复制功能(我已经删除GUI回调):@H_403_4@
procedure CustomFileCopy(const ASourceFileName,ADestinationFileName: TFileName);
const
BufferSize = 1024; // 1KB blocks,change this to tune your speed
var
Buffer : array of Byte;
ASourceFile,ADestinationFile: THandle;
FileSize: DWORD;
BytesRead,BytesWritten,BytesWritten2: DWORD;
begin
SetLength(Buffer,BufferSize);
ASourceFile := OpenLongFileName(ASourceFileName,0);
if ASourceFile <> 0 then
try
FileSize := FileSeek(ASourceFile,FILE_END);
FileSeek(ASourceFile,FILE_BEGIN);
ADestinationFile := CreateLongFileName(ADestinationFileName,FILE_SHARE_READ);
if ADestinationFile <> 0 then
try
while (FileSize - FileSeek(ASourceFile,FILE_CURRENT)) >= BufferSize do
begin
if (not ReadFile(ASourceFile,Buffer[0],BufferSize,BytesRead,nil)) and (BytesRead = 0) then
Continue;
WriteFile(ADestinationFile,nil);
if BytesWritten < BytesRead then
begin
WriteFile(ADestinationFile,Buffer[BytesWritten],BytesRead - BytesWritten,BytesWritten2,nil);
if (BytesWritten2 + BytesWritten) < BytesRead then
RaiseLastOSError;
end;
end;
if FileSeek(ASourceFile,FILE_CURRENT) < FileSize then
begin
if (not ReadFile(ASourceFile,FileSize - FileSeek(ASourceFile,FILE_CURRENT),nil)) and (BytesRead = 0) then
ReadFile(ASourceFile,nil);
WriteFile(ADestinationFile,nil);
if (BytesWritten2 + BytesWritten) < BytesRead then
RaiseLastOSError;
end;
end;
finally
CloseHandle(ADestinationFile);
end;
finally
CloseHandle(ASourceFile);
end;
end;
function OpenLongFileName(const ALongFileName: String; SharingMode: DWORD): THandle; overload;
begin
if CompareMem(@(ALongFileName[1]),@('\\'[1]),2) then
{ Allready an UNC path }
Result := CreateFileW(PWideChar(WideString(ALongFileName)),GENERIC_READ,SharingMode,nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0)
else
Result := CreateFileW(PWideChar(WideString('\\?\' + ALongFileName)),0);
end;
function OpenLongFileName(const ALongFileName: WideString; SharingMode: DWORD): THandle; overload;
begin
if CompareMem(@(WideCharToString(PWideChar(ALongFileName))[1]),2) then
{ Allready an UNC path }
Result := CreateFileW(PWideChar(ALongFileName),0)
else
Result := CreateFileW(PWideChar('\\?\' + ALongFileName),0);
end;
function CreateLongFileName(const ALongFileName: String; SharingMode: DWORD): THandle; overload;
begin
if CompareMem(@(ALongFileName[1]),GENERIC_WRITE,CREATE_ALWAYS,0);
end;
function CreateLongFileName(const ALongFileName: WideString; SharingMode: DWORD): THandle; overload;
begin
if CompareMem(@(WideCharToString(PWideChar(ALongFileName))[1]),0);
end;
代码有一点需要,因为我包括一个重试机制来支持我有一个wifi连接问题。@H_403_4@
所以这部分@H_403_4@
if BytesWritten < BytesRead then
begin
WriteFile(ADestinationFile,nil);
if (BytesWritten2 + BytesWritten) < BytesRead then
RaiseLastOSError;
end;
可以写成@H_403_4@
if BytesWritten < BytesRead then
begin
RaiseLastOSError;
end;
>你可以调用使用的CopyFile
CopyFileA windows API@H_403_4@
>你可以调用浏览器使用的api(windows api
SHFileOperation)。一个例子
调用该函数可以找到
SCIP.be
>你可以编写自己的使用缓冲区的函数。@H_403_4@
如果您知道要复制的文件类型,则第3种方法通常会胜过其他方式。因为Windows API更适合整体最佳情况(小文件,大文件,网络上的文件,慢驱动器上的文件)。您可以根据需要调整自己的复印功能。@H_403_4@
以下是我自己的缓冲复制功能(我已经删除GUI回调):@H_403_4@
procedure CustomFileCopy(const ASourceFileName,ADestinationFileName: TFileName); const BufferSize = 1024; // 1KB blocks,change this to tune your speed var Buffer : array of Byte; ASourceFile,ADestinationFile: THandle; FileSize: DWORD; BytesRead,BytesWritten,BytesWritten2: DWORD; begin SetLength(Buffer,BufferSize); ASourceFile := OpenLongFileName(ASourceFileName,0); if ASourceFile <> 0 then try FileSize := FileSeek(ASourceFile,FILE_END); FileSeek(ASourceFile,FILE_BEGIN); ADestinationFile := CreateLongFileName(ADestinationFileName,FILE_SHARE_READ); if ADestinationFile <> 0 then try while (FileSize - FileSeek(ASourceFile,FILE_CURRENT)) >= BufferSize do begin if (not ReadFile(ASourceFile,Buffer[0],BufferSize,BytesRead,nil)) and (BytesRead = 0) then Continue; WriteFile(ADestinationFile,nil); if BytesWritten < BytesRead then begin WriteFile(ADestinationFile,Buffer[BytesWritten],BytesRead - BytesWritten,BytesWritten2,nil); if (BytesWritten2 + BytesWritten) < BytesRead then RaiseLastOSError; end; end; if FileSeek(ASourceFile,FILE_CURRENT) < FileSize then begin if (not ReadFile(ASourceFile,FileSize - FileSeek(ASourceFile,FILE_CURRENT),nil)) and (BytesRead = 0) then ReadFile(ASourceFile,nil); WriteFile(ADestinationFile,nil); if (BytesWritten2 + BytesWritten) < BytesRead then RaiseLastOSError; end; end; finally CloseHandle(ADestinationFile); end; finally CloseHandle(ASourceFile); end; end;
function OpenLongFileName(const ALongFileName: String; SharingMode: DWORD): THandle; overload; begin if CompareMem(@(ALongFileName[1]),@('\\'[1]),2) then { Allready an UNC path } Result := CreateFileW(PWideChar(WideString(ALongFileName)),GENERIC_READ,SharingMode,nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0) else Result := CreateFileW(PWideChar(WideString('\\?\' + ALongFileName)),0); end; function OpenLongFileName(const ALongFileName: WideString; SharingMode: DWORD): THandle; overload; begin if CompareMem(@(WideCharToString(PWideChar(ALongFileName))[1]),2) then { Allready an UNC path } Result := CreateFileW(PWideChar(ALongFileName),0) else Result := CreateFileW(PWideChar('\\?\' + ALongFileName),0); end; function CreateLongFileName(const ALongFileName: String; SharingMode: DWORD): THandle; overload; begin if CompareMem(@(ALongFileName[1]),GENERIC_WRITE,CREATE_ALWAYS,0); end; function CreateLongFileName(const ALongFileName: WideString; SharingMode: DWORD): THandle; overload; begin if CompareMem(@(WideCharToString(PWideChar(ALongFileName))[1]),0); end;
代码有一点需要,因为我包括一个重试机制来支持我有一个wifi连接问题。@H_403_4@
所以这部分@H_403_4@
if BytesWritten < BytesRead then begin WriteFile(ADestinationFile,nil); if (BytesWritten2 + BytesWritten) < BytesRead then RaiseLastOSError; end;
可以写成@H_403_4@
if BytesWritten < BytesRead then begin RaiseLastOSError; end;