封装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指针传给回调函数(此方法也是之前在网上找到的)。
好了,最后贴上代码。(由于涉及到了多线程,对于多线程的同步还没做,但是实际中貌似没发现影响。还有其它众多地方不太完善)。
-
-
-
-
-
-
-
-
-
-
- #pragma once
-
- #define WM_COPYFILE_NOTIFY WM_USER+118+2 //自定义的windows消息,用来通知窗口
-
- class FileCopy
- {
- private:
- LPTSTR lpExistingPathName;
- LPTSTR lpNewPathName;
- int iSpeedControl;
- BOOL bCancel;
- HANDLE hEvent_Pause;
- float fCopyProgress;
- HWND hNotifyWnd;
-
- HANDLE hEvent_End;
-
- HANDLE hThread_Copy;
-
- LARGE_INTEGER totalFileSize;
- LARGE_INTEGER totalBytesTransferred;
-
- int ret_PGR;
-
-
-
- void Initialize();
-
-
- static DWORD WINAPI ThreadProc_Copy(LPVOID lpParam);
-
-
-
- static DWORD CALLBACK CopyProgressRoutine(
- LARGE_INTEGER TotalFileSize,
- LARGE_INTEGER TotalBytesTransferred,
- LARGE_INTEGER StreamSize,
- LARGE_INTEGER StreamBytesTransferred,
- DWORD dwStreamNumber,
- DWORD dwCallbackReason,
- HANDLE hSourceFile,
- HANDLE hDestinationFile,
- LPVOID lpData
- );
-
- public:
- FileCopy(void);
-
-
- FileCopy(LPTSTR lpExistingPathName,LPTSTR lpNewPathName,HWND hNotifyWnd=NULL);
- ~FileCopy(void);
-
-
- BOOL Init(LPTSTR lpExistingPathName,LPTSTR lpNewPathName,HWND hNotifyWnd=NULL);
-
-
- BOOL Begin();
-
- void Pause();
-
- void Resume();
-
- void Cancel();
-
-
-
-
- void WaitForEnd();
-
-
- float GetProgress();
-
-
- DWORD GetTotalFileSize(DWORD* lpFileSizeHigh=NULL);
-
- DWORD GetBytesTransferred(DWORD* lpTransferredHigh=NULL);
-
-
- void SetSpeed(int iSpeed);
- };
-
-
-
-
-
-
- #include "StdAfx.h"
- #include "FileCopy.h"
-
- FileCopy::FileCopy(void)
- {
- Initialize();
- }
-
- FileCopy::FileCopy(LPTSTR lpExistingPathName,LPTSTR lpNewPathName,HWND hNotifyWnd)
- {
- Init(lpExistingPathName,lpNewPathName,hNotifyWnd);
- }
-
- FileCopy::~FileCopy(void)
- {
-
- CloseHandle(hEvent_End);
- CloseHandle(hEvent_Pause);
- CloseHandle(hThread_Copy);
- }
-
- void FileCopy::Initialize()
- {
- bCancel=FALSE;
- hNotifyWnd=NULL;
- fCopyProgress=0;
- hEvent_Pause=NULL;
- iSpeedControl=-1;
- totalFileSize.HighPart=0;
- totalFileSize.LowPart=0;
- totalBytesTransferred.HighPart=0;
- totalBytesTransferred.LowPart=0;
- hThread_Copy=NULL;
-
- ret_PGR=PROGRESS_CONTINUE;
-
-
- if(hEvent_End!=NULL)
- CloseHandle(hEvent_End);
- hEvent_End=CreateEvent(NULL,TRUE,FALSE,NULL);
-
-
- if(hEvent_Pause!=NULL)
- CloseHandle(hEvent_Pause);
- hEvent_Pause=CreateEvent(NULL,TRUE,TRUE,NULL);
- }
-
- BOOL FileCopy::Init(LPTSTR lpExistingPathName,LPTSTR lpNewPathName,HWND hNotifyWnd)
- {
- Initialize();
- this->lpExistingPathName=lpExistingPathName;
- this->lpNewPathName=lpNewPathName;
- this->hNotifyWnd=hNotifyWnd;
-
- HANDLE hFile=CreateFile(lpExistingPathName,GENERIC_READ,
- FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL,NULL);
- if(INVALID_HANDLE_VALUE==hFile)
- return FALSE;
- if(!GetFileSizeEx(hFile,&totalFileSize))
- return FALSE;
-
- return TRUE;
- }
-
- BOOL FileCopy::Begin()
- {
-
-
-
- hThread_Copy=CreateThread(NULL,0,ThreadProc_Copy,this,0,NULL);
- if(NULL==hThread_Copy)
- {
- return FALSE;
- }
-
- return TRUE;
- }
-
-
- DWORD WINAPI FileCopy::ThreadProc_Copy(LPVOID lpParam)
- {
-
- HWND hNotifyWnd=((FileCopy*)lpParam)->hNotifyWnd;
- LPTSTR lpExistingPathName=((FileCopy*)lpParam)->lpExistingPathName;
- LPTSTR lpNewPathName=((FileCopy*)lpParam)->lpNewPathName;
-
-
- BOOL bSucceed=CopyFileEx(lpExistingPathName,lpNewPathName,
- CopyProgressRoutine,
- lpParam,&(((FileCopy*)lpParam)->bCancel),
- COPY_FILE_ALLOW_DECRYPTED_DESTINATION|COPY_FILE_COPY_SYMLINK|COPY_FILE_FAIL_IF_EXISTS);
-
-
- if(hNotifyWnd!=NULL)
- {
- if(bSucceed)
- {
- PostMessage(hNotifyWnd,WM_COPYFILE_NOTIFY,1,(LPARAM)lpExistingPathName);
- }
- else
- {
- PostMessage(hNotifyWnd,WM_COPYFILE_NOTIFY,0,(LPARAM)lpExistingPathName);
- }
- }
-
-
- SetEvent(((FileCopy*)lpParam)->hEvent_End);
- return 0;
- }
-
- DWORD CALLBACK FileCopy::CopyProgressRoutine(
- LARGE_INTEGER TotalFileSize,
- LARGE_INTEGER TotalBytesTransferred,
- LARGE_INTEGER StreamSize,
- LARGE_INTEGER StreamBytesTransferred,
- DWORD dwStreamNumber,
- DWORD dwCallbackReason,
- HANDLE hSourceFile,
- HANDLE hDestinationFile,
- LPVOID lpData
- )
- {
-
- ((FileCopy*)lpData)->totalFileSize=TotalFileSize;
- ((FileCopy*)lpData)->totalBytesTransferred=TotalBytesTransferred;
-
-
- ((FileCopy*)lpData)->fCopyProgress=TotalBytesTransferred.QuadPart*1.0/TotalFileSize.QuadPart;
-
-
- WaitForSingleObject(((FileCopy*)lpData)->hEvent_Pause,INFINITE);
-
-
- int iSpeed=((FileCopy*)lpData)->iSpeedControl;
- if(iSpeed>=0)
- Sleep(iSpeed);
-
- return PROGRESS_CONTINUE;
- }
-
- void FileCopy::Pause()
- {
- ResetEvent(hEvent_Pause);
- }
-
- void FileCopy::Resume()
- {
- SetEvent(hEvent_Pause);
- }
-
- void FileCopy::Cancel()
- {
- bCancel=TRUE;
- Resume();
- }
-
- void FileCopy::WaitForEnd()
- {
- WaitForSingleObject(hEvent_End,INFINITE);
- }
-
- float FileCopy::GetProgress()
- {
- return fCopyProgress;
- }
-
- DWORD FileCopy::GetTotalFileSize(DWORD* lpFileSizeHigh)
- {
- if(lpFileSizeHigh)
- *lpFileSizeHigh=totalFileSize.HighPart;
- return totalFileSize.LowPart;
- }
-
- DWORD FileCopy::GetBytesTransferred(DWORD* lpTransferredHigh)
- {
- if(lpTransferredHigh)
- *lpTransferredHigh=totalBytesTransferred.HighPart;
- return totalBytesTransferred.LowPart;
- }
-
- void FileCopy::SetSpeed(int iSpeed)
- {
- iSpeedControl=iSpeed;
-
- if(iSpeedControl>1000)
- iSpeedControl=1000;
- }
更正:代码中的LPTSTR变量类型应改成LPCTSTR,否者不能传入CString类型参数。
更正后的下载地址
http://download.csdn.net/detail/career2011/3657624