原文链接:
文件和文件夹的创建、复制、删除、重命名等操作是经常要用到的,作者根据自己的经验,并查询了MSDN,特意总结了常用文件和文件夹的相关操作,重点讨论了复制整个文件夹和删除整个文件夹
1、文件操作基本函数
WinBase.h中声明了Windows平台下的基本的API函数,包括文件和目录的基本操作。
下面列出部分常用的文件操作相关函数。
函数 | 说明 |
DeleteFile | 删除单个文件,不能删除目录和只读文件 |
CopyFile | 复制单个文件 |
MoveFile | 移动移动文件或目录 |
CreateDirectory | 创建目录 |
RemoveDirectory | 删除空目录 |
更多的函数可查询Winbase.h文件或者MSDN中的File Management Functions和Directory Management Functions 。
2、复制目录和删除目录
WinBase.h中的文件操作函数中并没有直接实现整个文件夹的复制和删除操作的函数,需要自己实现。
(1)判断指定路径是否有效目录
1 /*判断一个路径是否是已存在的目录*/ 2 BOOL IsDirectory(LPCTSTR pstrPath) 3 { 4 if (NULL == pstrPath) 5 { 6 return FALSE; 7 } 8 9 /*去除路径末尾的反斜杠*/ 10 CString strPath = pstrPath; 11 if (strPath.Right(1) == _T('\\')) 12 { 13 strPath.Delete(strPath.GetLength()-1); 14 } 15 16 CFileFind finder; 17 BOOL bRet = finder.FindFile(strPath); 18 if (!bRet) 19 { 20 return FALSE; 21 } 22 23 /*判断该路径是否是目录*/ 24 finder.FindNextFile(); 25 bRet = finder.IsDirectory(); 26 finder.Close(); 27 return bRet; 28 }
(2)复制目录
复制目录函数的大致思路为:查找目录中所有文件,如果是文件直接复制,如果是目录,则递归调用目录复制函数。
1 /*复制目录中的所有内容*/ 2 BOOL CopyFolder(LPCTSTR pstrSrcFolder, LPCTSTR pstrDstFolder) 3 { 4 if ((NULL == pstrSrcFolder) || (NULL == pstrSrcFolder)) 5 { 6 return FALSE; 7 } 8 9 /*检查源目录是否是合法目录*/ 10 if (!IsDirectory(pstrSrcFolder)) 11 { 12 return FALSE; 13 } 14 15 /*把文件名称转换为CString类型,并确认目录的路径末尾为反斜杠*/ 16 CString strSrcFolder(pstrSrcFolder); 17 if (strSrcFolder.Right(1) != _T('\\')) 18 { 19 strSrcFolder += _T("\\"); 20 } 21 CString strDstFolder(pstrDstFolder); 22 if (strDstFolder.Right(1) != _T("\\")) 23 { 24 strDstFolder += _T("\\"); 25 } 26 27 /*如果是目录自身复制,直接返回复制成功*/ 28 if (0 == _tcscmp(strSrcFolder, strDstFolder)) 29 { 30 return TRUE; 31 } 32 33 /*如果目的目录不存在,则创建目录*/ 34 if (!IsDirectory(strDstFolder)) 35 { 36 if (!CreateDirectory(strDstFolder, NULL)) 37 { 38 /*创建目的目录失败*/ 39 return FALSE; 40 } 41 } 42 43 /*创建源目录中查找文件的通配符*/ 44 CString strWildcard(strSrcFolder); 45 strWildcard += _T("*.*"); 46 47 /*打开文件查找,查看源目录中是否存在匹配的文件*/ 48 /*调用FindFile后,必须调用FindNextFile才能获得查找文件的信息*/ 49 CFileFind finder; 50 BOOL bWorking = finder.FindFile(strWildcard); 51 52 while (bWorking) 53 { 54 /*查找下一个文件*/ 55 bWorking = finder.FindNextFile(); 56 57 /*跳过当前目录“.”和上一级目录“..”*/ 58 if (finder.IsDots()) 59 { 60 continue; 61 } 62 63 /*得到当前要复制的源文件的路径*/ 64 CString strSrcFile = finder.GetFilePath(); 65 66 /*得到要复制的目标文件的路径*/ 67 CString strDstFile(strDstFolder); 68 strDstFile += finder.GetFileName(); 69 70 /*判断当前文件是否是目录,*/ 71 /*如果是目录,递归调用复制目录,*/ 72 /*否则,直接复制文件*/ 73 if (finder.IsDirectory()) 74 { 75 if (!CopyFolder(strSrcFile, strDstFile)) 76 { 77 finder.Close(); 78 return FALSE; 79 } 80 } 81 else 82 { 83 if (!CopyFile(strSrcFile, strDstFile, FALSE)) 84 { 85 finder.Close(); 86 return FALSE; 87 } 88 } 89 90 } /*while (bWorking)*/ 91 92 /*关闭文件查找*/ 93 finder.Close(); 94 95 return TRUE; 96 97 }
(3)删除目录
删除目录的思路和复制目录的思路类似,也是采用递归的方法。
1 /*删除目录及目录中的所有内容*/ 2 BOOL DeleteFolder(LPCTSTR pstrFolder) 3 { 4 if ((NULL == pstrFolder)) 5 { 6 return FALSE; 7 } 8 9 /*检查输入目录是否是合法目录*/ 10 if (!IsDirectory(pstrFolder)) 11 { 12 return FALSE; 13 } 14 15 /*创建源目录中查找文件的通配符*/ 16 CString strWildcard(pstrFolder); 17 if (strWildcard.Right(1) != _T('\\')) 18 { 19 strWildcard += _T("\\"); 20 } 21 strWildcard += _T("*.*"); 22 23 /*打开文件查找,查看源目录中是否存在匹配的文件*/ 24 /*调用FindFile后,必须调用FindNextFile才能获得查找文件的信息*/ 25 CFileFind finder; 26 BOOL bWorking = finder.FindFile(strWildcard); 27 28 while (bWorking) 29 { 30 /*查找下一个文件*/ 31 bWorking = finder.FindNextFile(); 32 33 /*跳过当前目录“.”和上一级目录“..”*/ 34 if (finder.IsDots()) 35 { 36 continue; 37 } 38 39 /*得到当前目录的子文件的路径*/ 40 CString strSubFile = finder.GetFilePath(); 41 42 /*判断当前文件是否是目录,*/ 43 /*如果是目录,递归调用删除目录,*/ 44 /*否则,直接删除文件*/ 45 if (finder.IsDirectory()) 46 { 47 if (!DeleteFolder(strSubFile)) 48 { 49 finder.Close(); 50 return FALSE; 51 } 52 } 53 else 54 { 55 if (!DeleteFile(strSubFile)) 56 { 57 finder.Close(); 58 return FALSE; 59 } 60 } 61 62 } /*while (bWorking)*/ 63 64 /*关闭文件查找*/ 65 finder.Close(); 66 67 /*删除空目录*/ 68 return RemoveDirectory(pstrFolder); 69 }
3、shlwapi.h中的文件操作函数
shlwapi.h是shlwapi.dll头文件,shlwapi.dll(Microsoft Shell Light-weight Utility Library)中定义了路径相关的操作,也包括了部分文件操作函数。由于shlwapi.dll属于Microsoft Windows Shell,因此这些文件操作特点与通过Shell进行文件操作类似。
下面列出部分常用的文件操作相关函数。
PathIsDirectory | 判断一个路径是否有效目录 |
PathIsDirectoryEmpty | 判断一个路径是否空目录 |
PathFileExists | 判断一个路径是否有效目录或文件 |
PathRenameExtension | 更改文件的后缀名 |
SHFileOperation | 可实现文件或目录的复制、移动、重命名和删除操作,并可一次操作多个文件或目录 |
其中,SHFileOperation可实现整个目录的内容的复制和删除。SHFileOperation可一次实现多个目录的复制或删除,其输入参数结构体SHFILEOPSTRUCT中的pFrom(源目录)和pTo(目的目录)都可以输入多个目录,目录之间通过'\0'分割,pFrom和pTo必须以2个'\0'结尾。一般情况下,我们都只是对一个目录操作,因此,SHFileOperation调用并不是很方便,下面就对SHFileOperation进行包装,提供更方便调用的目录操作函数。
具体的代码实现如下:
(1)复制目录
1 /*通过调用ShFileOperation来实现整个目录的复制*/ 2 /*只复制单个目录*/ 3 /*如果目标目录已存在,将把源目录作为目的目录的子目录*/ 4 /*如果要实现完全覆盖,需要先删除目的目录*/ 5 BOOL SHCopyFolder(LPCTSTR pstrSrcFolder, LPCTSTR pstrDstFolder) 6 { 7 if ((NULL == pstrSrcFolder) || (NULL == pstrSrcFolder)) 8 { 9 return FALSE; 10 } 11 12 int iSrcPathLen = _tcslen(pstrSrcFolder); 13 int iDstPathLen = _tcslen(pstrDstFolder); 14 if ((iSrcPathLen >= MAX_PATH) || (iDstPathLen >= MAX_PATH)) 15 { 16 return FALSE; 17 } 18 19 /*确保源目录的路径以2个\0结尾*/ 20 TCHAR tczSrcFolder[MAX_PATH+1]; 21 ZeroMemory(tczSrcFolder, (MAX_PATH+1)*sizeof(TCHAR)); 22 _tcscpy(tczSrcFolder, pstrSrcFolder); 23 tczSrcFolder[iSrcPathLen] = _T('\0'); 24 tczSrcFolder[iSrcPathLen+1] = _T('\0'); 25 26 /*确保目的目录的路径以2个\0结尾*/ 27 TCHAR tczDstFolder[MAX_PATH+1]; 28 ZeroMemory(tczDstFolder, (MAX_PATH+1)*sizeof(TCHAR)); 29 _tcscpy(tczDstFolder, pstrDstFolder); 30 tczDstFolder[iDstPathLen] = _T('\0'); 31 tczDstFolder[iDstPathLen+1] = _T('\0'); 32 33 SHFILEOPSTRUCT FileOp; 34 ZeroMemory(&FileOp, sizeof(SHFILEOPSTRUCT)); 35 FileOp.fFlags |= FOF_SILENT; /*不显示进度*/ 36 FileOp.fFlags |= FOF_NOERRORUI ; /*不报告错误信息*/ 37 FileOp.fFlags |= FOF_NOCONFIRMATION;/*不进行确认*/ 38 FileOp.hNameMappings = NULL; 39 FileOp.hwnd = NULL; 40 FileOp.lpszProgressTitle = NULL; 41 FileOp.wFunc = FO_COPY; 42 FileOp.pFrom = tczSrcFolder; /*源目录,必须以2个\0结尾*/ 43 FileOp.pTo = tczDstFolder; /*目的目录,必须以2个\0结尾*/ 44 45 /*复制目录*/ 46 if (0 == SHFileOperation(&FileOp)) 47 { 48 return TRUE; 49 } 50 else 51 { 52 return FALSE; 53 } 54 55 }
(2)删除目录
1 /*通过调用ShFileOperation来实现整个目录的删除*/ 2 /*只删除单个目录*/ 3 BOOL CFolder::SHDeleteFolder(LPCTSTR pstrFolder, BOOL bAllowUndo) 4 { 5 if ((NULL == pstrFolder)) 6 { 7 return FALSE; 8 } 9 10 int iPathLen = _tcslen(pstrFolder); 11 if (iPathLen >= MAX_PATH) 12 { 13 return FALSE; 14 } 15 16 /*确保目录的路径以2个\0结尾*/ 17 TCHAR tczFolder[MAX_PATH+1]; 18 ZeroMemory(tczFolder, (MAX_PATH+1)*sizeof(TCHAR)); 19 _tcscpy(tczFolder, pstrFolder); 20 tczFolder[iPathLen] = _T('\0'); 21 tczFolder[iPathLen+1] = _T('\0'); 22 23 SHFILEOPSTRUCT FileOp; 24 ZeroMemory(&FileOp, sizeof(SHFILEOPSTRUCT)); 25 FileOp.fFlags |= FOF_SILENT; /*不显示进度*/ 26 FileOp.fFlags |= FOF_NOERRORUI; /*不报告错误信息*/ 27 FileOp.fFlags |= FOF_NOCONFIRMATION;/*直接删除,不进行确认*/ 28 FileOp.hNameMappings = NULL; 29 FileOp.hwnd = NULL; 30 FileOp.lpszProgressTitle = NULL; 31 FileOp.wFunc = FO_DELETE; 32 FileOp.pFrom = tczFolder; /*要删除的目录,必须以2个\0结尾*/ 33 FileOp.pTo = NULL; 34 35 /*根据传递的bAllowUndo参数确定是否删除到回收站*/ 36 if (bAllowUndo) 37 { 38 FileOp.fFlags |= FOF_ALLOWUNDO; /*删除到回收站*/ 39 } 40 else 41 { 42 FileOp.fFlags &= ~FOF_ALLOWUNDO; /*直接删除,不放入回收站*/ 43 } 44 45 /*删除目录*/ 46 if (0 == SHFileOperation(&FileOp)) 47 { 48 return TRUE; 49 } 50 else 51 { 52 return FALSE; 53 } 54 }
4、示例工程
作者通过VC6.0和VS2010分别针对以上代码创建了示例工程,在工程中,把以上函数封装到CFolder类中,并把所有函数设置为静态函数。在示例工程中,分别对这些函数进行了调用测试。
工程文件下载:
PUDN:
CSDN:
5、参考资料
(1)、File Management Functions
(2)、Directory Management Functions