我正在编写一个应用程序,它应该将一堆文件从一个地方复制到另一个地方.当我使用TFileStream进行复制时,它比使用操作系统复制文件慢3-4倍.
我也尝试用缓冲区复制,但这太慢了.
我在Win32下工作,有人对此事有一些见解吗?
有几个选择.
您可以调用使用CopyFileA Windows API 的CopyFile
你可以调用探险家使用的api(windows api SHFileOperation).可以在SCIP.be上找到调用该函数的 示例
您可以编写自己的使用缓冲区的函数.
如果您知道要复制的文件类型,第3种方法通常会优于其他方法.因为windows API更适合整体最佳情况(小文件,大文件,网络文件,慢速驱动器上的文件).您可以更多地调整自己的复制功能以满足您的需求.
下面是我自己的缓冲复制功能(我已经删除了GUI回调):
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, 0, FILE_END); FileSeek(ASourceFile, 0, FILE_BEGIN); ADestinationFile := CreateLongFileName(ADestinationFileName, FILE_SHARE_READ); if ADestinationFile <> 0 then try while (FileSize - FileSeek(ASourceFile, 0, FILE_CURRENT)) >= BufferSize do begin if (not ReadFile(ASourceFile, Buffer[0], BufferSize, BytesRead, nil)) and (BytesRead = 0) then Continue; WriteFile(ADestinationFile, Buffer[0], BytesRead, BytesWritten, 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, 0, FILE_CURRENT) < FileSize then begin if (not ReadFile(ASourceFile, Buffer[0], FileSize - FileSeek(ASourceFile, 0, FILE_CURRENT), BytesRead, nil)) and (BytesRead = 0) then ReadFile(ASourceFile, Buffer[0], FileSize - FileSeek(ASourceFile, 0, FILE_CURRENT), BytesRead, nil); WriteFile(ADestinationFile, Buffer[0], BytesRead, BytesWritten, nil); if BytesWritten < BytesRead then begin WriteFile(ADestinationFile, Buffer[BytesWritten], BytesRead - BytesWritten, BytesWritten2, 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)), GENERIC_READ, SharingMode, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); end; function OpenLongFileName(const ALongFileName: WideString; SharingMode: DWORD): THandle; overload; begin if CompareMem(@(WideCharToString(PWideChar(ALongFileName))[1]), @('\\'[1]), 2) then { Allready an UNC path } Result := CreateFileW(PWideChar(ALongFileName), GENERIC_READ, SharingMode, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0) else Result := CreateFileW(PWideChar('\\?\' + ALongFileName), GENERIC_READ, SharingMode, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); end; function CreateLongFileName(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_WRITE, SharingMode, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0) else Result := CreateFileW(PWideChar(WideString('\\?\' + ALongFileName)), GENERIC_WRITE, SharingMode, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); end; function CreateLongFileName(const ALongFileName: WideString; SharingMode: DWORD): THandle; overload; begin if CompareMem(@(WideCharToString(PWideChar(ALongFileName))[1]), @('\\'[1]), 2) then { Allready an UNC path } Result := CreateFileW(PWideChar(ALongFileName), GENERIC_WRITE, SharingMode, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0) else Result := CreateFileW(PWideChar('\\?\' + ALongFileName), GENERIC_WRITE, SharingMode, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); end;
代码有点长,因为我包含了一个重试机制来支持我的wifi连接问题.
这一部分
if BytesWritten < BytesRead then begin WriteFile(ADestinationFile, Buffer[BytesWritten], BytesRead - BytesWritten, BytesWritten2, nil); if (BytesWritten2 + BytesWritten) < BytesRead then RaiseLastOSError; end;
可写成
if BytesWritten < BytesRead then begin RaiseLastOSError; end;