////////////////////////////////////////////////////////////
// 文件夹拷贝高效实现. VC++6.0 控制台实现
// 作者:liujichao8567#163.com
// 转载请邮件通知作者,谢谢!
///////////////////////////////////////////////////////////
// 头文件包含
#include <wtypes.h>
#include <winnt.h>
#include <shellapi.h>
#include <io.h>
#include <tchar.h>
#include <map>
#include <string>
// 设置连接器选项,不弹出控制台窗口
#pragma comment(linker, "/subsystem:windows /entry:mainCRTStartup")
////////////////////////////////////////////////////////////
// 宏定义
// 返回错误码
#define RETCODE_SUCCESS 0 // 真
#define RETCODE_FAILURE -1 // 假
// 数组长度
#define _countof(a) (sizeof(a) / sizeof(a[0]))
////////////////////////////////////////////////////////////
// 错误码
// 错误码表
TCHAR* g_szErrorMsgTable[] =
{
_T("待拷贝源文件夹不存在。"),
_T("删除指定文件夹失败。"),
_T("访问待删除文件夹时失败。"),
_T("查找删除文件夹下子文件失败。"),
_T("目的文件夹路径不正确,拷贝文件失败。"),
_T("应用程序执行删除文件时操作失败。"),
_T("应用程序执行拷贝文件时操作失败。")
};
// 错误码起始号
#define ERROR_CODE_BEGIN_INDEX 0x10000
// 错误码ID列表
#define ACCESS_COPY_FILE_FAILURE (ERROR_CODE_BEGIN_INDEX + 0)
#define DELETE_TARGET_FOLDER_FAILURE (ERROR_CODE_BEGIN_INDEX + 1)
#define ACCESS_DELETE_FILE_FAILURE (ERROR_CODE_BEGIN_INDEX + 2)
#define FIND_DELETE_SUBFILE_FAILURE (ERROR_CODE_BEGIN_INDEX + 3)
#define TARGET_FOLDER_PATH_IS_INVALID (ERROR_CODE_BEGIN_INDEX + 4)
#define EXEC_DELETE_FILE_FAILURE (ERROR_CODE_BEGIN_INDEX + 5)
#define EXEC_COPY_FILE_FAILURE (ERROR_CODE_BEGIN_INDEX + 6)
// 定义错误码信息结构体类型
struct ERRORINFO
{
std::string strFileName; // 出错源文件
int iLineNum; // 出错代码行
int iErrorCode; // 错误码
ERRORINFO()
{
strFileName = "";
iLineNum = -1;
iErrorCode = -1;
}
};
ERRORINFO g_stErrorInfo;
// 通过错误码ID取得对应的错误码字符串
#define GetErrorMessage(error_code) (g_szErrorMsgTable[error_code - ERROR_CODE_BEGIN_INDEX])
// 设置自定义错误
void SetLastError(int iErrCode)
{
// Release版本中去掉错误提示(无日志支持)
#ifdef _DEBUG
g_stErrorInfo.iErrorCode = iErrCode;
g_stErrorInfo.strFileName = __FILE__;
g_stErrorInfo.iLineNum = __LINE__;
#endif
}
// 弹出错误信息提示对话框
void AfxErrorMessageBox()
{
TCHAR szErrMsg[MAX_PATH];
memset(&szErrMsg, 0, _countof(szErrMsg) * sizeof(TCHAR));
if ( -1 != g_stErrorInfo.iErrorCode )
{
// 错误提示信息
wsprintf(szErrMsg, _T("源文件路径: %s\n\n代码所在行: %d\n\n错误信息: %s"), g_stErrorInfo.strFileName.c_str(),
g_stErrorInfo.iLineNum, GetErrorMessage(g_stErrorInfo.iErrorCode));
// 弹出错误提示对话框
::MessageBox(NULL, szErrMsg, _T("应用程序出错"), MB_OK | MB_ICONEXCLAMATION);
}
}
//////////////////////////////////////////////////////
// 函数原型声明
BOOL CopyFolder(LPCTSTR lpszExistingFolderName, LPCTSTR lpszNewFolderName, BOOL bOverWrite);
BOOL DeleteFolder(LPCTSTR lpszExistringFolderName, BOOL bOnlyChild);
//////////////////////////////////////////////////////////
// 主函数入口
int main(int argc, char* argv[])
{
if ( !CopyFolder("D:\\1", "G:\\DB", TRUE) )
{
AfxErrorMessageBox();
return -1;
}
return 0;
}
///////////////////////////////////////////////////////////////
// 函数实现
// 文件夹拷贝函数
// lpszExistingFolderName : 源文件夹
// lpszNewFolderName : 宿文件夹
// bOverWrite : 是否覆盖标记
// return : 拷贝成功返回true,失败返回false
BOOL CopyFolder(LPCTSTR lpszExistingFolderName, LPCTSTR lpszNewFolderName, BOOL bOverWrite)
{
// 源文件夹不存在
if ( RETCODE_FAILURE == ::access(lpszExistingFolderName, 0) )
{
SetLastError(ACCESS_COPY_FILE_FAILURE);
return FALSE;
}
// 目标文件夹存在
if ( RETCODE_SUCCESS == ::access(lpszNewFolderName, 0) )
{
// 覆盖模式下,先行删除目的文件夹内容
if ( bOverWrite )
{
if ( !DeleteFolder(lpszNewFolderName, TRUE) )
{
SetLastError(DELETE_TARGET_FOLDER_FAILURE);
return FALSE;
}
}
}
else
{
// 创建目的文件夹
if ( !::CreateDirectory(lpszNewFolderName, NULL) )
{
SetLastError(TARGET_FOLDER_PATH_IS_INVALID);
return FALSE;
}
}
// 构造拷贝命令
SHFILEOPSTRUCT sh;
memset(&sh, 0, sizeof(SHFILEOPSTRUCT));
sh.wFunc = FO_COPY;
sh.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR | FOF_NOERRORUI;
sh.pFrom= lpszExistingFolderName;
sh.pTo = lpszNewFolderName;
// 执行命令
if ( RETCODE_FAILURE == ::SHFileOperation(&sh) )
{
SetLastError(EXEC_COPY_FILE_FAILURE);
return FALSE;
}
return TRUE;
}
// 文件夹删除函数
// lpszExistringFolderName : 待删除文件夹路径
// bOnlyChild : 是否仅删除子文件/文件夹标记
// return : 删除成功返回true,失败返回false
BOOL DeleteFolder(LPCTSTR lpszExistringFolderName, BOOL bOnlyChild)
{
// 判断待删除文件夹是否存在
if ( RETCODE_FAILURE == ::access(lpszExistringFolderName, 0) )
{
SetLastError(ACCESS_DELETE_FILE_FAILURE);
return FALSE;
}
// 仅删除子文件和子文件夹
if ( bOnlyChild )
{
WIN32_FIND_DATA stFileInfo;
memset(&stFileInfo, 0, sizeof(WIN32_FIND_DATA));
// 查找第一个文件
TCHAR szPath[MAX_PATH];
memset(&szPath, 0, _countof(szPath) * sizeof(TCHAR));
wsprintf(szPath, _T("%s\\%s"), lpszExistringFolderName, _T("*.*"));
HANDLE hFile = FindFirstFile(szPath, &stFileInfo);
if ( INVALID_HANDLE_VALUE == hFile )
{
SetLastError(FIND_DELETE_SUBFILE_FAILURE);
return FALSE;
}
// 遍历所有文件
do
{
// 过滤系统文件夹
if ( '.' == stFileInfo.cFileName[0] )
{
continue;
}
// 删除文件/文件夹
else
{
memset(&szPath, 0, _countof(szPath) * sizeof(TCHAR));
wsprintf(szPath, _T("%s\\%s"), lpszExistringFolderName, stFileInfo.cFileName);
if ( !DeleteFolder(szPath, FALSE) )
{
SetLastError(DELETE_TARGET_FOLDER_FAILURE);
return FALSE;
}
}
} while (::FindNextFile(hFile, &stFileInfo) );
::FindClose(hFile);
}
else
{
// 构造删除命令
SHFILEOPSTRUCT sh;
memset(&sh, 0, sizeof(SHFILEOPSTRUCT));
sh.wFunc = FO_DELETE;
sh.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR | FOF_NOERRORUI;
sh.pFrom = lpszExistringFolderName;
// 执行删除操作
if ( RETCODE_FAILURE == ::SHFileOperation(&sh) )
{
SetLastError(EXEC_DELETE_FILE_FAILURE);
return FALSE;
}
}
return TRUE;
}