封装CopyFileEx函数,实现文件复制中的暂停,控速,获取进度

2023-05-16

封装CopyFileEx函数,实现文件复制中的暂停,控速,获取进度等。


前段时间无意间想到如何控制文件复制过程的复制速度,并且能实时获得复制进度。对于一个几兆甚至更小的文件,调用API函数CopyFile(Ex)来复制,很快就能完成的。然而对于一个几百兆的大文件来说,如果仍然采用调用同步CopyFileEx,那么函数将阻塞相当长的时间。并且对于大文件我更希望能知道复制的进度。为此,百度谷歌了很长时间(也曾在csdn发过帖子http://topic.csdn.net/u/20110730/16/8ebd7515-83f6-4868-8d7c-2d7a783cda8b.html在此感谢各位坛友的帮助),得知CopyFileEx这个函数能实现我的要求。因此用自己那点浅薄的C++知识对CopyFileEx函数进行了简单的封装,算是实现了自己的需求。今天把之前的代码整理了下,写在自己的csdn博客上,一来算是为自己整理下思路,锻炼下自己的文字描述能力,二来,也想获得各位前辈的指点,若能给那些和我当初一样迷茫的童鞋一个参考,实乃万幸。

想想这也是我自己的第一篇博客,菜鸟一个,不怕拍砖!吼吼!^_^ 

CopyFileEx函数原型
BOOL WINAPI CopyFileEx(
  __in      LPCTSTR lpExistingFileName,
  __in      LPCTSTR lpNewFileName,
  __in_opt  LPPROGRESS_ROUTINE lpProgressRoutine,
  __in_opt  LPVOID lpData,
  __in_opt  LPBOOL pbCancel,
  __in      DWORD dwCopyFlags
);
前两个参数很容易明白,既然是复制文件的函数肯定要有源文件和目标文件了。第三个参数是一个回调函数的地址,在复制过程中,每当复制完成一块数据之后便调用一次,回调函数返回后再继续复制过程。如果再回调函数中让线程Sleep()一定的时间,便能减缓整个复制过程的速度,在回调函数中让线程暂定也就能暂停整个复制过程了。第四个数lpData是传给回调函数的参数,可以将在回调函数中需要修改的数据通过指针的方式传入。lpCancel:函数在执行过程中会不断的检测它指向的数值,一旦为TRUE便会取消复制过程。因此,可以用它来实现复制的停止。最后一个参数指示函数执行过程中的一些其它行为,不是非常关心,这里不在赘述。
对于回调函数
WORD CALLBACK CopyProgressRoutine(
  __in      LARGE_INTEGER TotalFileSize,
  __in      LARGE_INTEGER TotalBytesTransferred,
  __in      LARGE_INTEGER StreamSize,
  __in      LARGE_INTEGER StreamBytesTransferred,
  __in      DWORD dwStreamNumber,
  __in      DWORD dwCallbackReason,
  __in      HANDLE hSourceFile,
  __in      HANDLE hDestinationFile,
  __in_opt  LPVOID lpData
);
系统给我们传入很多有用的数据。可以看到有文件长度,已经拷贝的字节数,每个数据块的长度,回调原因,甚至包括源文件和目标文件的句柄(这里我对第3,4,5这个三个参数并不是十分理解,不过影响不大~)等等。lpData就是之前我们传入的指针。很显然,通过TotalBytesTransferred与TotalFileSize的比值我们就能知道复制进度。另外这个函数返回不同的值也有不同的作用。基本原理就是这样。

为了能让CopyFileEx不阻塞当前线程,我在类中创建新的线程来调用它,当CopyFileEx返回时通过PostMessage发送窗口消息来通知应用程序文件复制的结果。
要封装成类,但是这里用到了两个回调函数(线程回调函数和CopyFileEx的回调函数),而回调函数只能是全局函数,因此我将两个回调函数都写成类的静态函数,为了能方便访问类中的成员变量又将this指针传给回调函数(此方法也是之前在网上找到的)。

好了,最后贴上代码。(由于涉及到了多线程,对于多线程的同步还没做,但是实际中貌似没发现影响。还有其它众多地方不太完善)。

[cpp]  view plain copy
  1. /************************************************************************** 
  2. 文件名:CopyFile.h 
  3. 文件说明:类FileCopy头文件 
  4. 简要说明:封装CopyFileEx函数,实现文件复制过程的暂停,控速,异步与同步。创建新的 
  5.     线程,并在其中调用CopyFileEx函数,利用CopyFileEx的回调函数实现暂停,控制速度, 
  6.     获取进度等功能。 
  7. 完成日期:21:14 2011/10/4 
  8. 备注:代码不够完善,没能做好线程同步工作,有时间再去改进! 
  9. **************************************************************************/  
  10.   
  11. #pragma once  
  12.   
  13. #define  WM_COPYFILE_NOTIFY WM_USER+118+2  //自定义的windows消息,用来通知窗口  
  14.   
  15. class FileCopy  
  16. {  
  17. private:  
  18.     LPTSTR lpExistingPathName;                   //源文件  
  19.     LPTSTR lpNewPathName;               //目标文件  
  20.     int iSpeedControl;                  //速度控制的变量  
  21.     BOOL bCancel;                       //取消标志,用来传入CopyFileEx的回调函数  
  22.     HANDLE  hEvent_Pause;               //“复制暂停”事件  
  23.     float fCopyProgress;                //复制进度  
  24.     HWND hNotifyWnd;                    //接受通知消息的窗口  
  25.   
  26.     HANDLE hEvent_End;                  //“复制结束”事件  
  27.   
  28.     HANDLE hThread_Copy;                //线程句柄  
  29.   
  30.     LARGE_INTEGER totalFileSize;                 //总的文件长度     
  31.     LARGE_INTEGER totalBytesTransferred;    //已经复制的字节数  
  32.   
  33.     int ret_PGR;                         //作为CopyProgressRoutine的返回值,此参数未用  
  34.   
  35.   
  36.   
  37.     void Initialize();   //初始化内部数据:各种句柄和变量;  
  38.   
  39.     //线程函数,在线程中调用CopyFileEx实现文件复制  
  40.     static DWORD WINAPI ThreadProc_Copy(LPVOID lpParam);  
  41.   
  42.   
  43.     //CopyFileEx的回调函数,在此函数中实现文件复制过程的控制。  
  44.     static DWORD CALLBACK CopyProgressRoutine(  
  45.         LARGE_INTEGER TotalFileSize,  
  46.         LARGE_INTEGER TotalBytesTransferred,  
  47.         LARGE_INTEGER StreamSize,  
  48.         LARGE_INTEGER StreamBytesTransferred,  
  49.         DWORD dwStreamNumber,  
  50.         DWORD dwCallbackReason,  
  51.         HANDLE hSourceFile,  
  52.         HANDLE hDestinationFile,  
  53.         LPVOID lpData  
  54.         );  
  55.   
  56. public:  
  57.     FileCopy(void);  
  58.   
  59.     //可以在构造函数中初始化数据  
  60.     FileCopy(LPTSTR lpExistingPathName,LPTSTR lpNewPathName,HWND hNotifyWnd=NULL);  
  61.     ~FileCopy(void);  
  62.   
  63.     //初始化必要的参数,源文件和目标文件  
  64.     BOOL Init(LPTSTR lpExistingPathName,LPTSTR lpNewPathName,HWND hNotifyWnd=NULL);  
  65.   
  66.     //开始拷贝过程  
  67.     BOOL Begin();  
  68.     //暂停复制  
  69.     void Pause();  
  70.     //恢复复制  
  71.     void Resume();  
  72.     //取消复制  
  73.     void Cancel();  
  74.     //停止复制  
  75.     //void Stop();     //Stop();结束复制过程,但保存已经复制的内容,Cancel();会删除已复制的内容。  
  76.   
  77.     //等待复制结束,用来实现“同步”效果,调用此函数后线程会阻塞,直到复制完成或取消。  
  78.     void WaitForEnd();  
  79.       
  80.     //获取复制进度  
  81.     float GetProgress();  
  82.     //获取文件总大小,函数返回方式模仿 API GetFileSize();   一般情况下超过4GB的文件不多  
  83.     //,lpFileSizeHigh直接忽视就行了  
  84.     DWORD GetTotalFileSize(DWORD* lpFileSizeHigh=NULL);  
  85.     //获取已经复制的字节数;  
  86.     DWORD GetBytesTransferred(DWORD* lpTransferredHigh=NULL);  
  87.   
  88.     //设置复制速度  
  89.     void SetSpeed(int iSpeed);  
  90. };  
[cpp]  view plain copy
  1.    
[cpp]  view plain copy
  1.    
[cpp]  view plain copy
  1. /************************************************************************** 
  2. 文件名:CopyFile.cpp 
  3. 文件说明:类FileCopy实现文件,详细信息见FileCopy.h文件 
  4. 完成日期:21:14 2011/10/4 
  5. **************************************************************************/  
  6.   
  7. #include "StdAfx.h"  
  8. #include "FileCopy.h"  
  9.   
  10. FileCopy::FileCopy(void)  
  11. {  
  12.     Initialize();  
  13. }  
  14.   
  15. FileCopy::FileCopy(LPTSTR lpExistingPathName,LPTSTR lpNewPathName,HWND hNotifyWnd)  
  16. {  
  17.     Init(lpExistingPathName,lpNewPathName,hNotifyWnd);  
  18. }  
  19.   
  20. FileCopy::~FileCopy(void)  
  21. {  
  22. //这里貌似做的不够好。。。。。-_-  
  23.     CloseHandle(hEvent_End);  
  24.     CloseHandle(hEvent_Pause);  
  25.     CloseHandle(hThread_Copy);  
  26. }  
  27.   
  28. void FileCopy::Initialize()  
  29. {  
  30.     bCancel=FALSE;  
  31.     hNotifyWnd=NULL;  
  32.     fCopyProgress=0;  
  33.     hEvent_Pause=NULL;  
  34.     iSpeedControl=-1;  
  35.     totalFileSize.HighPart=0;  
  36.     totalFileSize.LowPart=0;  
  37.     totalBytesTransferred.HighPart=0;  
  38.     totalBytesTransferred.LowPart=0;  
  39.     hThread_Copy=NULL;  
  40.   
  41.     ret_PGR=PROGRESS_CONTINUE;  
  42.   
  43.     //初始化 “复制结束”事件        手动重置  无信号  
  44.     if(hEvent_End!=NULL)  
  45.         CloseHandle(hEvent_End);  
  46.     hEvent_End=CreateEvent(NULL,TRUE,FALSE,NULL);  
  47.   
  48.     //初始化 “复制暂停”事件,       手动重置  有信号状态  
  49.     if(hEvent_Pause!=NULL)  
  50.         CloseHandle(hEvent_Pause);  
  51.     hEvent_Pause=CreateEvent(NULL,TRUE,TRUE,NULL);  
  52. }  
  53.   
  54. BOOL FileCopy::Init(LPTSTR lpExistingPathName,LPTSTR lpNewPathName,HWND hNotifyWnd/* =NULL */)  
  55. {  
  56.     Initialize();  
  57.     this->lpExistingPathName=lpExistingPathName;  
  58.     this->lpNewPathName=lpNewPathName;  
  59.     this->hNotifyWnd=hNotifyWnd;  
  60.   
  61.     HANDLE hFile=CreateFile(lpExistingPathName,GENERIC_READ,  
  62.         FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,  
  63.         FILE_ATTRIBUTE_NORMAL,NULL);  
  64.     if(INVALID_HANDLE_VALUE==hFile)  
  65.         return FALSE;  
  66.     if(!GetFileSizeEx(hFile,&totalFileSize))  
  67.         return FALSE;  
  68.   
  69.     return TRUE;  
  70. }  
  71.   
  72. BOOL FileCopy::Begin()  
  73. {  
  74.     //在线程中调用CopyFileEx函数,为了保持类的封装性,  
  75.     //线程函数被写成类的静态成员函数,此处传入this指针为了访问成员变量  
  76.     //CopyFileEx的回调函数也是类似于这样实现的。  
  77.     hThread_Copy=CreateThread(NULL,0,ThreadProc_Copy,this,0,NULL);  
  78.     if(NULL==hThread_Copy)  
  79.     {  
  80.         return FALSE;  
  81.     }  
  82.   
  83.     return TRUE;  
  84. }  
  85.   
  86.   
  87. DWORD WINAPI FileCopy::ThreadProc_Copy(LPVOID lpParam)  
  88. {  
  89.     //获得当前类的实例中的相关数据  
  90.     HWND hNotifyWnd=((FileCopy*)lpParam)->hNotifyWnd;  
  91.     LPTSTR lpExistingPathName=((FileCopy*)lpParam)->lpExistingPathName;  
  92.     LPTSTR lpNewPathName=((FileCopy*)lpParam)->lpNewPathName;  
  93.   
  94.     //调用核心API函数CopyFileEx来复制文件  
  95.     BOOL bSucceed=CopyFileEx(lpExistingPathName,lpNewPathName,  
  96.         CopyProgressRoutine,  
  97.         lpParam,&(((FileCopy*)lpParam)->bCancel),  
  98.         COPY_FILE_ALLOW_DECRYPTED_DESTINATION|COPY_FILE_COPY_SYMLINK|COPY_FILE_FAIL_IF_EXISTS);  
  99.   
  100.     //拷贝结束,向窗口发送通知消息;  
  101.     if(hNotifyWnd!=NULL)  
  102.     {  
  103.         if(bSucceed)  
  104.         {  
  105.             PostMessage(hNotifyWnd,WM_COPYFILE_NOTIFY,1,(LPARAM)lpExistingPathName);  
  106.         }  
  107.         else  
  108.         {  
  109.             PostMessage(hNotifyWnd,WM_COPYFILE_NOTIFY,0,(LPARAM)lpExistingPathName);  
  110.         }  
  111.     }  
  112.   
  113.     //将“拷贝结束”事件设置成信号状态  
  114.     SetEvent(((FileCopy*)lpParam)->hEvent_End);  
  115.     return 0;  
  116. }  
  117.   
  118. DWORD CALLBACK FileCopy::CopyProgressRoutine(  
  119.     LARGE_INTEGER TotalFileSize,  
  120.     LARGE_INTEGER TotalBytesTransferred,  
  121.     LARGE_INTEGER StreamSize,  
  122.     LARGE_INTEGER StreamBytesTransferred,  
  123.     DWORD dwStreamNumber,  
  124.     DWORD dwCallbackReason,  
  125.     HANDLE hSourceFile,  
  126.     HANDLE hDestinationFile,  
  127.     LPVOID lpData  
  128.     )  
  129. {  
  130. //保存文件长度和已经复制的数据量  
  131.     ((FileCopy*)lpData)->totalFileSize=TotalFileSize;  
  132.     ((FileCopy*)lpData)->totalBytesTransferred=TotalBytesTransferred;  
  133.   
  134. //计算复制进度  
  135.     ((FileCopy*)lpData)->fCopyProgress=TotalBytesTransferred.QuadPart*1.0/TotalFileSize.QuadPart;  
  136.   
  137. //通过事件对象实现暂停;  
  138.     WaitForSingleObject(((FileCopy*)lpData)->hEvent_Pause,INFINITE);  
  139.   
  140. //通过Sleep()来控制复制速度  
  141.     int iSpeed=((FileCopy*)lpData)->iSpeedControl;  
  142.     if(iSpeed>=0)  
  143.         Sleep(iSpeed);  
  144. //返回0,继续复制,以通过bCancel控制复制结束,此返回值暂时未用  
  145.     return PROGRESS_CONTINUE;  
  146. }  
  147.   
  148. void FileCopy::Pause()  
  149. {  
  150.     ResetEvent(hEvent_Pause);  
  151. }  
  152.   
  153. void FileCopy::Resume()  
  154. {  
  155.     SetEvent(hEvent_Pause);  
  156. }  
  157.   
  158. void FileCopy::Cancel()  
  159. {  
  160.     bCancel=TRUE;  
  161.     Resume();       //恢复暂停状态,让线程自然结束!  
  162. }  
  163.   
  164. void FileCopy::WaitForEnd()  
  165. {  
  166.     WaitForSingleObject(hEvent_End,INFINITE);  
  167. }  
  168.   
  169. float FileCopy::GetProgress()  
  170. {  
  171.     return fCopyProgress;  
  172. }  
  173.   
  174. DWORD FileCopy::GetTotalFileSize(DWORD* lpFileSizeHigh)  
  175. {  
  176.     if(lpFileSizeHigh)  
  177.         *lpFileSizeHigh=totalFileSize.HighPart;  
  178.     return totalFileSize.LowPart;  
  179. }  
  180.   
  181. DWORD FileCopy::GetBytesTransferred(DWORD* lpTransferredHigh)  
  182. {  
  183.     if(lpTransferredHigh)  
  184.         *lpTransferredHigh=totalBytesTransferred.HighPart;  
  185.     return totalBytesTransferred.LowPart;  
  186. }  
  187.   
  188. void FileCopy::SetSpeed(int iSpeed)  
  189. {  
  190.     iSpeedControl=iSpeed;  
  191. //每次线程Sleep()的时间不超过1000ms  
  192.     if(iSpeedControl>1000)  
  193.         iSpeedControl=1000;  
  194. }  


更正:代码中的LPTSTR变量类型应改成LPCTSTR,否者不能传入CString类型参数。

更正后的下载地址

http://download.csdn.net/detail/career2011/3657624
 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

封装CopyFileEx函数,实现文件复制中的暂停,控速,获取进度 的相关文章

随机推荐

  • 软件项目产品化之路

    软件项目产品化之路 2 产品化之路 2 1 困惑 软件项目产品化是大量软件企业 xff0c 特别是应用型软件研发企业所必须面临的问题 不论是小型的软件公司和中大型的软件企业 xff0c 在面对软件项目和软件产品 xff0c 都有诸多困惑 到
  • 软件产品化的一些见解

    软件产品化的定义 软件产品化 即客户无需为软件添加或调整代码和语句即能完成软件的安装配置 应用初始化 系统管理 用户使用的全过程 并且软件至少能满足80 以上的用户某一组应用需求 软件产品化只是完成了产品的生产环节 后面的产品销售 市场推广
  • 程序员与工匠精神

    前几天和一个朋友聊天时说 xff1a 我有强迫症 xff0c 每次看到不符合自己审美的代码时 xff0c 总想重构一下 朋友的观点与大多数人相仿 xff0c 程序只要满足要求 xff0c 运行正确就可以 在现实的工作中一样 xff0c 每当
  • linux 进程线程思维导图

  • 修改结构体中成员的值

    include lt iostream gt using namespace std struct student char name 10 float grade 更改student数据的grade成员 xff0c 参数形式为引用 voi
  • C++中冒号的用法

    1 冒号 xff08 xff09 用法 xff08 1 xff09 表示机构内位域的定义 xff08 即该变量占几个bit空间 xff09 typedef struct XXX unsigned char a 4 unsigned char
  • C/C++预处理指令

    本文主要记录了C C 43 43 预处理指令 xff0c 常见的预处理指令如下 xff1a 空指令 xff0c 无任何效果 include包含一个源代码文件 define定义宏 undef取消已定义的宏 if如果给定条件为真 xff0c 则
  • STM32F1常用外设介绍(超详细35000字介绍)

    STM32学习笔记 GPIO配置步骤 步骤 xff1a 第一步 xff0c 使用RCC开启GPIO的时钟 第二步 xff0c 使用GPIO Init 函数初始化GPIO 第三步 xff0c 使用输出或者输入的函数控制GPIO口 常用的RCC
  • MFC拷贝文件及进度条显示

    参考 xff1a 封装CopyFileEx函数 xff0c 实现文件复制中的暂停 xff0c 控速 xff0c 获取进度 http blog csdn net career2011 article details 6844513 实例讲解C
  • 什么是寄存器?(STM32)

    什么是寄存器 xff1f 我们现在在开发STM32时 xff0c 已经很少用到寄存器编程 xff0c 更多的使用ST公司所提供的标准库和最新的HAL库进行编程实现 xff0c 但是不管是标准库还是HAL库都是在原来的寄存器层面上进行了封装
  • 计算机网络——物理层(一)

    物理层 xff08 部分 xff09 机械特性 xff1a 指明接口所用接线器的形状和尺寸 引脚数目和排列 固定和锁定装置等 电气特性 xff1a 指明在接口电缆的各条线上出现的电压的范围 功能特性 xff1a 指明某条线上出现的某一电平的
  • 洛谷P5717-三角形分类

    洛谷P5717 三角形分类 题目 这道题更像是初中题 xff0c 但是怎么能完整的按照题目的意思来解决呢 xff0c 说实话这个题卡了我有一会儿 xff0c 要做一次性做出这个题 xff0c 我觉得需要搞清楚if if 和if else i
  • 洛谷P1424-小鱼的航程(改进版)

    洛谷P1424 小鱼的航程 xff08 改进版 xff09 这个题我第一次做的时候 xff0c 有两个没过 xff0c 后来检查的时候发现原来是没有考虑开始的时间是不是周六周日 xff0c 如果是周六要在原来的天数上 2 xff0c 如果是
  • freertos-简介(一)

    FreeRTOS 裸机 不带任何操作系统 只能先打完游戏回复信息 实时性差 xff0c 程序轮流执行delay空等待 xff0c CPU不执行其他代码结构臃肿 xff0c 实现功能都在while循环 RTOS 实时操作系统 会执行打游戏一个
  • PCB设计过程中AD使用流程详解(超详细)

    PCB设计过程中AD使用流程详解 xff08 超详细 xff09 1 设计前期部分 规则设定 xff1a Preference system file type关联文件 xff08 所有关联 xff09 PCB editor General
  • python面向对象编程

    符合python风格的对象 先来看一个向量类的例子 span class token keyword class span span class token class name Vector2d span span class token
  • DIY 一个树莓派无人机

    学习目标 xff1a DIY 一个树莓派无人机 这篇文章来源于DevicePlus com英语网站的翻译稿 提示 xff1a 这里可以添加学习目标 学习内容 xff1a 提示 xff1a 这里可以添加要学的内容 今天 xff0c 我们将利用
  • Linux开源杀毒软件CLamAV介绍

    Linux开源杀毒软件CLamAV介绍 很多用户可能不知道在Linux上会有计算机病毒 xff0c 虽然Linux上的病毒不像在Windows上那么常见 xff0c 但实际上 xff0c 很多重要系统均采用Linux系统作为服务器的操作系统
  • vrpn_cient_ros发送频率无法调整提供解决思路

    最近写了节点来订阅ros client ros 但是发现在launch文件修改update frequency不起作用 xff0c 然而我又需要通过串口给下位机发送数据 xff0c 频率一快 xff0c 串口直接堵死了 怎么调都freque
  • 封装CopyFileEx函数,实现文件复制中的暂停,控速,获取进度

    封装CopyFileEx函数 xff0c 实现文件复制中的暂停 xff0c 控速 xff0c 获取进度等 前段时间无意间想到如何控制文件复制过程的复制速度 xff0c 并且能实时获得复制进度 对于一个几兆甚至更小的文件 xff0c 调用AP