随笔 - 2146  文章 - 19 评论 - 11846 阅读 - 1267万


function CopyFileEx(
  lpExistingFileName: PWideChar;         { 源文件 }
  lpNewFileName: PWideChar;              { 新的目标文件 }
  lpProgressRoutine: TFNProgressRoutine; { 回调函数; 每复制 64K 调用一次 }
  lpData: Pointer;                       { 给回调函数的参数 }
  pbCancel: PBool;                       { 是个布尔值指针; True 是取消复制 }
  dwCopyFlags: DWORD                     { 复制选项; 下面有补充... }
): BOOL; stdcall;                        { 返回成功或失败 }

//dwCopyFlags(复制选项):
COPY_FILE_FAIL_IF_EXISTS = $00000001; { 如果目标存在则失败返回 }
COPY_FILE_RESTARTABLE    = $00000002; { 若失败则重新开始 }

//CopyFileEx 使用的回调函数: function ProgressRoutine(   TotalFileSize: LARGE_INTEGER;          { 文件总字节数 }   TotalBytesTransferred: LARGE_INTEGER;  { 已复制的字节数 }   StreamSize: LARGE_INTEGER;            { 当前流的字节数 }   StreamBytesTransferred: LARGE_INTEGER; { 当前流已拷贝的字节数 }   dwStreamNumber: DWORD;                { 当前流序号 }   dwCallbackReason: DWORD;              { 回调函数的状态; 下面有补充... }   hSourceFile: THANDLE;                  { 源文件句柄 }   hDestinationFile: THANDLE;            { 目标文件句柄 }   lpData: Pointer                        { CopyFileEx 传递的参数指针 } ): DWORD; stdcall;                      { 返回值; 下面有补充... } //dwCallbackReason(回调函数的状态): CALLBACK_CHUNK_FINISHED = $00000000; { 复制进行中 } CALLBACK_STREAM_SWITCH  = $00000001; { 准备开始} //回调函数可以使用的返回值: PROGRESS_CONTINUE = 0; { 继续 } PROGRESS_CANCEL  = 1; { 取消 } PROGRESS_STOP    = 2; { 暂停 } PROGRESS_QUIET    = 3; { 终止回调, 但不停止复制 }

一个实现复制进度的测试, 测试前在窗体上放个 TProgressBar:

//回调函数; 为了运算我把其中的 LARGE_INTEGER 类型改成 Int64 了
function ProgressRoutine(TotalFileSize, TotalBytesTransferred, StreamSize,
  StreamBytesTransferred: Int64; dwStreamNumber, dwCallbackReason: DWORD;
  hSourceFile, hDestinationFile: THANDLE; lpData: Pointer): DWORD; stdcall;
begin
  Form1.ProgressBar1.Position := Trunc(TotalBytesTransferred / TotalFileSize * 100);
  Application.ProcessMessages;
  Result := PROGRESS_CONTINUE;
end;

//复制
procedure TForm1.Button1Click(Sender: TObject);
const
  s = 'C:\Temp\Test.rar';
  d = 'C:\Temp\NewDir\Test.rar';
begin
  Assert(FileExists(s), '源文件不存在');
  Assert(DirectoryExists(ExtractFilePath(d)), '目标路径不存在');
  CopyFileEx(PChar(s), PChar(d), @ProgressRoutine, nil, nil, COPY_FILE_RESTARTABLE);
end;

posted on   万一  阅读(6587)  评论(5编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
历史上的今天:
2009-01-08 提取网页中的所有链接、点击第 n 个链接 - 回复 "刘丽" 的问题
2008-01-08 Delphi 中的 XMLDocument 类详解(21) - 暂停
2008-01-08 Delphi 中的 XMLDocument 类详解(20) - 动态建立 XMLDocument 对象


点击右上角即可分享
微信分享提示