平時寫程序時經常會用到的遍歷子目錄枚舉文件的功能,用Windows API 函數FindFirstFile() 和FindNextFile() 直接實現起來會相當繁瑣,有許多細節需要注意和記憶,要在短時間內寫出可以正常工作的、沒有BUG的、能夠遞歸遍歷多層子目錄並枚舉其中所有文件的程序代碼,不是一件輕松的事情。以下這個doFileEnumeration() 函數,是我(liigo)在Windows API 函數FindFirstFile() 和FindNextFile() 的基礎上封裝實現的,可以輕松自如的處理遍歷子目錄枚舉文件的任務,使用起來非常簡單,具有較高的實用價值。這個函數其實是我之前發布的易語言“輔助調試支持庫”(已開源至googlecode)中“枚舉文件”“枚舉子目錄”這兩條命令的底層實現函數。
doFileEnumeration() 函數功能是實現枚舉文件和枚舉子目錄,支持遞歸處理多層子目錄嵌套的情況。它有五個參數:第一個參數lpPath指定欲遍歷的路徑(文件夾);第二個參數bRecursion指定是否遞歸處理子目錄;第三個參數bEnumFiles指定是枚舉文件還是枚舉子目錄;第四個參數pFunc為用戶回調函數,枚舉過程中每遇到一個文件或子目錄,都會調用它,並傳入這個文件或子目錄的完整路徑;第五個參數pUserData為用戶任意指定的數據,它也將被傳入用戶回調函數。用戶回調函數(EnumerateFunc)有兩個參數,一個是文件或子目錄的完整路徑(lpFileOrPath),一個是用戶自定義數據(pUserData),它被自動調用,用戶需在此函數中編碼處理代碼。
這個函數經過我(liigo)的仔細設計,接口很簡潔,使用也方便。有意去除了FindFirstFile(Ex)/FindNextFile 中過濾文件名稱或屬性的部分功能,也是出於簡化接口的考慮,——在用戶回調函數中處理這些事情也是很容易的(在易語言中更容易)。在實現的細節上,重點是對子目錄和遞歸的處理。以下是完整的源代碼:
#include <windows.h>
typedef BOOL (WINAPI *EnumerateFunc) (LPCSTR lpFileOrPath, void* pUserData);
void doFileEnumeration(LPSTR lpPath, BOOL bRecursion, BOOL bEnumFiles, EnumerateFunc pFunc, void* pUserData)
{
static BOOL s_bUserBreak = FALSE;
try{
//-------------------------------------------------------------------------
if(s_bUserBreak) return;
int len = strlen(lpPath);
if(lpPath==NULL || len<=0) return;
//NotifySys(NRS_DO_EVENTS, 0,0);
char path[MAX_PATH];
strcpy(path, lpPath);
if(lpPath[len-1] != '\\') strcat(path, "\\");
strcat(path, "*");
WIN32_FIND_DATA fd;
HANDLE hFindFile = FindFirstFile(path, &fd);
if(hFindFile == INVALID_HANDLE_VALUE)
{
::FindClose(hFindFile); return;
}
char tempPath[MAX_PATH]; BOOL bUserReture=TRUE; BOOL bIsDirectory;
BOOL bFinish = FALSE;
while(!bFinish)
{
strcpy(tempPath, lpPath);
if(lpPath[len-1] != '\\') strcat(tempPath, "\\");
strcat(tempPath, fd.cFileName);
bIsDirectory = ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0);
//如果是.或.. www.2cto.com
if( bIsDirectory
&& (strcmp(fd.cFileName, ".")==0 || strcmp(fd.cFileName, "..")==0))
{
bFinish = (FindNextFile(hFindFile, &fd) == FALSE);
continue;
}
if(pFunc && bEnumFiles!=bIsDirectory)
{
bUserReture = pFunc(tempPath, pUserData);
if(bUserReture==FALSE)
{
s_bUserBreak = TRUE; ::FindClose(hFindFile); return;
}
}
//NotifySys(NRS_DO_EVENTS, 0,0);
if(bIsDirectory && bRecursion) //是子目錄
{
doFileEnumeration(tempPath, bRecursion, bEnumFiles, pFunc, pUserData);
}
bFinish = (FindNextFile(hFindFile, &fd) == FALSE);
}
::FindClose(hFindFile);
//-------------------------------------------------------------------------
}catch(...){ ASSERT(0); return; }
}
BOOL WINAPI myEnumerateFunc(LPCSTR lpFileOrPath, void* pUserData)
{
char* pdot;
if((pdot = strrchr(lpFileOrPath, '.')) && stricmp(pdot, ".mp3") == 0)
{
printf("%s\n", lpFileOrPath);
}
return TRUE;
}
int main()
{
doFileEnumeration("C:\\Music", TRUE, TRUE, myEnumerateFunc, NULL);
return 0;
}
摘自 龍圖騰的博客