用CopyFile复制文件

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;  
}  



 

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值