文件夹拷贝函数高效实现

////////////////////////////////////////////////////////////
// 文件夹拷贝高效实现. 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;
}
posted on 2011-05-14 03:09  潇湘雨歇  阅读(1195)  评论(0编辑  收藏  举报