用CopyFile复制文件

来源:互联网 发布:清华 网络空间安全 编辑:程序博客网 时间:2024/06/07 10:19
BOOL CopyFile(LPCTSTR lpExistingFileName,LPCTSTR lpNewFileName,BOOL bFailIfExists );


说明  
  Long,非零表示成功,零表示失败。
  
参数类型及说明 :
  lpExistingFileName String:输入参数,已经存在的所需复制文件的源路径。
  lpNewFileName String:输入参数,新文件路径,复制文件的目的路径。

  bFailIfExists Long:输入参数,指明如果在目的路径存在文件时是否覆盖。如果设为TRUE(非零),将不覆盖已经存在的文件;如果存在,则返回失败。


返回值:
返回BOOL值,表示文件复制是否成功。


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;


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

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指针传给回调函数(此方法也是之前在网上找到的)。好了,最后贴上代码。(由于涉及到了多线程,对于多线程的同步还没做,但是实际中貌似没发现影响。还有其它众多地方不太完善)。view plain/************************************************************************** 文件名:CopyFile.h 文件说明:类FileCopy头文件 简要说明:封装CopyFileEx函数,实现文件复制过程的暂停,控速,异步与同步。创建新的     线程,并在其中调用CopyFileEx函数,利用CopyFileEx的回调函数实现暂停,控制速度,     获取进度等功能。 完成日期:21:14 2011/10/4 备注:代码不够完善,没能做好线程同步工作,有时间再去改进! **************************************************************************/    #pragma once    #define  WM_COPYFILE_NOTIFY WM_USER+118+2  //自定义的windows消息,用来通知窗口    class FileCopy  {  private:      LPTSTR lpExistingPathName;                   //源文件      LPTSTR lpNewPathName;               //目标文件      int iSpeedControl;                  //速度控制的变量      BOOL bCancel;                       //取消标志,用来传入CopyFileEx的回调函数      HANDLE  hEvent_Pause;               //“复制暂停”事件      float fCopyProgress;                //复制进度      HWND hNotifyWnd;                    //接受通知消息的窗口        HANDLE hEvent_End;                  //“复制结束”事件        HANDLE hThread_Copy;                //线程句柄        LARGE_INTEGER totalFileSize;                 //总的文件长度         LARGE_INTEGER totalBytesTransferred;    //已经复制的字节数        int ret_PGR;                         //作为CopyProgressRoutine的返回值,此参数未用            void Initialize();   //初始化内部数据:各种句柄和变量;        //线程函数,在线程中调用CopyFileEx实现文件复制      static DWORD WINAPI ThreadProc_Copy(LPVOID lpParam);          //CopyFileEx的回调函数,在此函数中实现文件复制过程的控制。      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 Stop();     //Stop();结束复制过程,但保存已经复制的内容,Cancel();会删除已复制的内容。        //等待复制结束,用来实现“同步”效果,调用此函数后线程会阻塞,直到复制完成或取消。      void WaitForEnd();            //获取复制进度      float GetProgress();      //获取文件总大小,函数返回方式模仿 API GetFileSize();   一般情况下超过4GB的文件不多      //,lpFileSizeHigh直接忽视就行了      DWORD GetTotalFileSize(DWORD* lpFileSizeHigh=NULL);      //获取已经复制的字节数;      DWORD GetBytesTransferred(DWORD* lpTransferredHigh=NULL);        //设置复制速度      void SetSpeed(int iSpeed);  };  view plain   view plain   view plain/************************************************************************** 文件名:CopyFile.cpp 文件说明:类FileCopy实现文件,详细信息见FileCopy.h文件 完成日期:21:14 2011/10/4 **************************************************************************/    #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/* =NULL */)  {      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()  {      //在线程中调用CopyFileEx函数,为了保持类的封装性,      //线程函数被写成类的静态成员函数,此处传入this指针为了访问成员变量      //CopyFileEx的回调函数也是类似于这样实现的。      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;        //调用核心API函数CopyFileEx来复制文件      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);    //通过Sleep()来控制复制速度      int iSpeed=((FileCopy*)lpData)->iSpeedControl;      if(iSpeed>=0)          Sleep(iSpeed);  //返回0,继续复制,以通过bCancel控制复制结束,此返回值暂时未用      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;  //每次线程Sleep()的时间不超过1000ms      if(iSpeedControl>1000)          iSpeedControl=1000;  }  



 

原创粉丝点击