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

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

更正后的下载地址

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

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

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

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

  2. [OpenCV] 练习题实现代码 使用 cv.addWeighted 函数在文件夹中创建图像的幻灯片放映,并在图像之间进行平滑过渡

    1.问题背景 opencv 官方手册 文档 练习题 练习题实现代码 使用 cv.addWeighted 函数在文件夹中创建图像的幻灯片放映,并在图像之间进行平滑过渡 2.代码部分 按任意键切换幻灯片 ...

  3. mfc 创建线程函数AfxBeginThread,线程中访问mfc控件

    转字http://blog.csdn.net/guomsh/article/details/10377993 1. C++ 中如何定义线程函数 有两种方法:a. 定义线程函数为全局函数    b. 定 ...

  4. python open函数创建文件_python中怎样使用open创建文件?

    我们在使用open函数的时候,一般用到的都是打开的功能,这和小伙伴们平常理解的名称意思是一致的.其实我们还可以使用open函数来创建一个file,也就是文本文件.在开始创建之前,我们需要对open函数 ...

  5. opencv3中的glob函数读取文件夹中数据

    glob函数的用法用法: glob在opencv3下,并且命名空间为cv::glob()能够直接调用,在官网中只说明了如下调用方式,并没有给出具体的例子.但通过使用可以知道函数目的是将pattern路 ...

  6. linux拷贝文件函数,如何使用Linux的splice()函数将文件复制到另一个文件?

    这是关于splice()的另一个问题.我希望用它来复制文件,我试图使用两个拼接调用,通过像splice维基百科页面上的例子一样的管道连接.我写了一个简单的测试用例,它只试图从一个文件读取前32K字节并 ...

  7. c语言头文件 数学函数,头文件cmath中常用函数

    里面有很多数学函数,下面说一下常用的一些函数吧:直接把函数原型给了出来,用的时候注意参数 1. double abs(int x)       一般对int型取绝对值后返回double型,不过也可以对 ...

  8. python 文件复制中出现 Python3之由通用字符名称“\u202A”表示的字符不能在当前代码页中表示出来

    with open('C:/Users/20346/Desktop/1.txt', "rb") as f:with open('C:/Users/20346/Desktop/2.t ...

  9. Android中的常用控件之进度条(ProgressBar)

    ProgressBar的常用属性 style(进度条的样式,默认为圆形:用style="?android:attr/progressBarStyleHorizontal"可以将进度 ...

最新文章

  1. SAP HANA:持续创新十周年
  2. SAP MM MIGO Cancellation可以用于冲销上次冲销而产生的物料凭证
  3. SQL SERVER DBCC命令解释
  4. 帮助企业降本增效,提高IT运营效率的六种方法
  5. 机器学习算法-随机森林之决策树R 代码从头暴力实现(2)
  6. springmvc全局异常处理ControllerAdvice区分返回响应类型是页面还是JSON
  7. 《嵌入式Linux软硬件开发详解——基于S5PV210处理器》——1.2 S5PV210处理器
  8. 适合做自动化测试的项目
  9. iOS开发之为什么更新UI都要放在主线程中
  10. mysql手册中文版
  11. Visio 2003 sp3下载
  12. Windows10中IE11浏览器的修复之路
  13. k3595参数_全系列三极管应用参数
  14. 验证计算机名出现一般性网络错误,一般性网络错误请检查网络文档
  15. 【Google面试题】有四个线程1、2、3、4同步写入数据…C++11实现
  16. Python os.symlink创建软链接
  17. Android播放音频到耳机,Android音乐播放模式切换-外放、听筒、耳机
  18. 多语言机器翻译 | (2) 编解码器结构
  19. 越权漏洞简介及靶场演示
  20. PDM系统在饲料工程设计中的应用

热门文章

  1. mysql购买服务_云数据库MySQL购买须知
  2. yyds、yygq、xswl...都是什么意思?
  3. 关于iOS自定义推送消息铃声
  4. trt-tl10ac01b220_android 7.0_emui 5.1,华为畅享7 plus固件TRT-TL10C01B201_Android 7.0_EMUI 5.1强刷救砖包...
  5. 人工智能对商业影响深远,AI可以为中小企业提供五大优势
  6. putty连接设备时报错 Can’t agree a key change algorithm
  7. joda-time 使用详解
  8. 关于Batch Normalization的理解和认识
  9. Camera2 闪光灯梳理
  10. 如何用计算机扫描图片变成文字,如何把文字图片或者扫描的文件变成word文档?详细步骤...