我正在写一个应用程序,它应该将一堆文件从一个地方复制到另一个地方。
当我使用TFileStream进行复制时,比使用操作系统复制文件要慢3-4倍。
当我使用TFileStream进行复制时,比使用操作系统复制文件要慢3-4倍。
我也试图用缓冲区复制,但是也太慢了。
我正在Win32工作,任何人都有这方面的见解?
解决方法
有几个选择。
>你可以调用使用的CopyFile
CopyFileA windows API
>你可以调用浏览器使用的api(windows api
SHFileOperation)。一个例子
调用该函数可以找到
SCIP.be
>你可以编写自己的使用缓冲区的函数。
如果您知道要复制的文件类型,则第3种方法通常会胜过其他方式。因为Windows API更适合整体最佳情况(小文件,大文件,网络上的文件,慢驱动器上的文件)。您可以根据需要调整自己的复印功能。
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连接问题。
所以这部分
if BytesWritten < BytesRead then begin WriteFile(ADestinationFile,nil); if (BytesWritten2 + BytesWritten) < BytesRead then RaiseLastOSError; end;
可以写成
if BytesWritten < BytesRead then begin RaiseLastOSError; end;