使用無型別檔案、檔案控制代碼、8KB 緩衝區、巢狀 try...finally 保護資源:
procedure CopyFile(const FileName, DestName: TFileName);
var CopyBuffer: Pointer; TimeStamp, BytesCopied: Longint; Source, Dest: Integer; Destination: TFileName;
const ChunkSize = 8192;
begin
Destination := ExpandFileName(DestName);
if HasAttr(Destination, faDirectory) then
Destination := Destination + '\' + ExtractFileName(FileName);
TimeStamp := FileAge(FileName);
GetMem(CopyBuffer, ChunkSize);
try
Source := FileOpen(FileName, fmShareDenyWrite);
if Source < 0 then raise EFOpenError.CreateFmt(SFOpenError, [FileName]);
try
Dest := FileCreate(Destination);
if Dest < 0 then raise EFCreateError.CreateFmt(SFCreateError, [Destination]);
try
repeat
BytesCopied := FileRead(Source, CopyBuffer^, ChunkSize);
if BytesCopied > 0 then FileWrite(Dest, CopyBuffer^, BytesCopied);
until BytesCopied < ChunkSize;
finally
FileSetDate(Dest, TimeStamp); FileClose(Dest);
end;
finally FileClose(Source); end;
finally FreeMem(CopyBuffer, ChunkSize); end;
end;
FileSetDate 保留原檔時間戳,否則 Windows 寫入當前時間。
優先嘗試 RenameFile(同磁碟機瞬間完成),失敗則「複製+刪除」:
procedure MoveFile(const FileName, DestName: TFileName);
var Destination: TFileName;
begin
Destination := ExpandFileName(DestName);
if not RenameFile(FileName, Destination) then
begin
if HasAttr(FileName, faReadOnly) then raise EFCantMove.CreateFmt(SFCantMove, [FileName]);
CopyFile(FileName, Destination);
DeleteFile(FileName);
end;
end;
EFCantMove 為自訂例外類別(class(EStreamError))。
直接呼叫 RTL 常式,執行前確認對話框,畢 FileList.Update 刷新顯示。