最近总是遇到需要遍历某路径下的所有文件并作出相应处理,总是有些收获的,也许对大神们来说都是些小case了。
需要做的是遍历某路径下的所有文件,那么路径自然是某个已知参数,我们需要考虑的有以下:
①路径是否合法,即路径是否存在,对于一个不存在的路径何须遍历了?
②windows下的每个文件夹下必定存在名为 “. ”和 “..” 这两个子文件夹,当你打开一个文件夹是看不到的,不过他们确确实实是存在的,不信就到cmd下CD到任意文件夹然后DIR试试吧,cmd是不会骗人的。“.” 代表自身,“..”为上级文件夹。遍历某一合法路径时势必会遇见这两个子文件夹,我们当然是不作处理,即排除他们。
③遍历到文件后我们需要做什么,也许你会说这不是遍历某一路径需要考虑的。当然,我们可以把这些交给另一个程序或者函数来处理,但是一个好的程序,应当留给其他程序一个好的接口,这自然也是我们该考虑的了。况且这也会影响到我们采用何种方法遍历。
④采用何种方法遍历,最为常见的也就是递归了吧,关于递归的好坏之处就不讨论了,先看看这种方法。
BOOL GoFind(char* lpszPath, char* scName){
TCHAR szFind[MAX_PATH];
TCHAR szFile[MAX_PATH];
TCHAR* extention;
lstrcpy(szFind, lpszPath);
if (!!IsRoot(szFind))
{//root dir
MessageBox( 0, "root dir", "111", MB_OK);
return FALSE;
}
lstrcat(szFind, "\\");
lstrcat(szFind, "*.*");
WIN32_FIND_DATA wfd;
HANDLE hFind = FindFirstFile(szFind, &wfd);
if (hFind == INVALID_HANDLE_VALUE)
{
MessageBox( 0, "INVALID_HANDLE_VALUE", "111", MB_OK);
return FALSE;
}
do
{
if (wfd.cFileName[0] == '.')
{//过滤.和..目录
continue;
}
if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{//文件夹
if (IsRoot(lpszPath))
{
wsprintf(szFile, "%s%s", lpszPath, wfd.cFileName);
}
else
{
wsprintf(szFile, "%s\\%s", lpszPath, wfd.cFileName);
}
GoFind(szFile, scName);//递归
}
else
{
extention = strrchr(wfd.cFileName , '.') + 1;//获取后缀名
wsprintf(szFile, "%s\\%s", lpszPath, wfd.cFileName);
//do Something
}
} while (FindNextFile(hFind, &wfd));
return TRUE;
}
上面已经提到对于遍历到得文件该做如何处理会影响到遍历方法的选取,上面这张遍历方法是鉴于对每种类型的文件,甚至每个文件分别处理而选取的方法。
如果你只是要复制某路径下的所有文件到其他地方,那么未必需呀递归了,递归效率低就不多做解释了。
void myCopyFile(CString strFromPath,CString strToPath,CString strFolderName)
{
try
{
CString strDstFolder = strToPath + _T("\\") + strFolderName;
if(!CValidFunction::IsPathExist(strDstFolder))
{
CValidFunction::CreatePath(strDstFolder);
}
CFileFind fileFind;
char szFileFind[MAX_PATH];
sprintf(szFileFind,"%s\\*.*",strFromPath);
BOOL bFinded = fileFind.FindFile(szFileFind);
while(bFinded)
{
char* srcpath = "C:\\";
float proportion = 5.0;
if (!HasEnoughSpace(srcpath, proportion))
{
break;
}
bFinded = fileFind.FindNextFile();
if(!fileFind.IsDots())
{
char szFileName[MAX_PATH];
strcpy(szFileName,fileFind.GetFileName().GetBuffer(MAX_PATH));
if(fileFind.IsDirectory())
{
char strNewFromPath[MAX_PATH];
sprintf(strNewFromPath,"%s\\%s", strFromPath, szFileName);
CopyFileEx(strNewFromPath, strDstFolder);//文件夹拷贝
Sleep(20);
}
else
{
char NewFileName[MAX_PATH],ExistFileName[MAX_PATH];
sprintf(ExistFileName,"%s\\%s",strFromPath,szFileName);
sprintf(NewFileName,"%s\\%s",strDstFolder,szFileName);
char fileext[10];
_splitpath(ExistFileName,NULL,NULL,NULL,fileext);
if (IsTextFile(fileext))
{
CopyFile(ExistFileName,NewFileName,FALSE);
}
Sleep(20);
}
}
}
fileFind.Close();
}
catch(...)
{
}
}
其中CopyFileEx的定义如下:
BOOL CopyFileEx(CString strFromPath,CString strToPath)
{
TCHAR chSplitter = '*';
strFromPath += chSplitter;
strToPath += chSplitter;
int len = strFromPath.GetLength();
TCHAR* pszSrcPath = strFromPath.GetBuffer(0);
for(int i = _tcslen(pszSrcPath) - 1; i >= 0; i --)
{
if(pszSrcPath[i] == chSplitter)
pszSrcPath[i] = '\0';
}
len = strToPath.GetLength();
TCHAR* pszDstPath = strToPath.GetBuffer(0);
for(i = _tcslen(pszDstPath) - 1; i >= 0; i --)
{
if(pszDstPath[i] == chSplitter)
pszDstPath[i] = '\0';
}
SHFILEOPSTRUCT FileOp;
ZeroMemory((void*)&FileOp,sizeof(SHFILEOPSTRUCT));
FileOp.fFlags = FOF_NOCONFIRMATION | FOF_SILENT;
FileOp.hNameMappings = NULL;
FileOp.hwnd = NULL;
FileOp.lpszProgressTitle = NULL;
FileOp.pFrom = pszSrcPath;
FileOp.pTo = pszDstPath;
FileOp.wFunc = FO_COPY;
int nRes = SHFileOperation(&FileOp);
return (nRes == 0);
}
这就不需要递归,效率会比较好。
当然,有的人偏好于递归,也不是不可以。like this:
void myCopyFile(CString strFromPath,CString strToPath,CString strFolderName)
{
try
{
CString strDstFolder = strToPath + _T("\\") + strFolderName;
if(!CValidFunction::IsPathExist(strDstFolder))
{
CValidFunction::CreatePath(strDstFolder);
}
CFileFind fileFind;
char szFileFind[MAX_PATH];
sprintf(szFileFind,"%s\\*.*",strFromPath);
BOOL bFinded = fileFind.FindFile(szFileFind);
while(bFinded)
{
char* srcpath = "C:\\";
float proportion = 5.0;
if (!HasEnoughSpace(srcpath, proportion))
{
break;
}
bFinded = fileFind.FindNextFile();
if(!fileFind.IsDots())
{
char szFileName[MAX_PATH];
strcpy(szFileName,fileFind.GetFileName().GetBuffer(MAX_PATH));
if(fileFind.IsDirectory())
{
char strNewFromPath[MAX_PATH];
sprintf(strNewFromPath,"%s\\%s", strFromPath, szFileName);
myCopyFile(strNewFromPath, strDstFolder, szFileName);//两端代码的不同之处
Sleep(20);
}
else
{
char NewFileName[MAX_PATH],ExistFileName[MAX_PATH];
sprintf(ExistFileName,"%s\\%s",strFromPath,szFileName);
sprintf(NewFileName,"%s\\%s",strDstFolder,szFileName);
char fileext[10];
_splitpath(ExistFileName,NULL,NULL,NULL,fileext);
if (IsTextFile(fileext))
{
CopyFile(ExistFileName,NewFileName,FALSE);
}
Sleep(20);
}
}
}
fileFind.Close();
}
catch(...)
{
}
}
其实两段代码的不同之处只有一句话,上面已经标出。
还是那句话吧,方法很多,更加高端的方法也很多,小弟愚见,只是总结了自己的一些方法而已。