沒看到能打的,遍歷目錄並讀取目錄下的檔案列表。(C語言,SDK)
遍歷目錄並讀取目錄下的所有檔案,這個功能經常用,也簡單,很多年前就看過網上的程式碼,感覺寫複雜了,而且還浪費棧,發文的人說會“爆棧”(而且還不是一個人)。當時看到那些程式碼就覺得寫的不好,不過覺得無關痛癢沒有發博文。
N年過去,遇到類似的情況,有點忍不住,這麼簡單的東西。今天專門去搜索了網上(擺渡和谷歌上面的程式碼,包括StackOverflow上面的程式碼,不禁說出周星星電影《破壞之王》裡面斷水流大師兄的那段話。
找到的程式碼,幾乎都是類似的,程式碼長,真浪費記憶體,速度又慢,還沒有錯誤判斷。
找一個稍好的例子。
bool ListDirectoryContents(const wchar_t *sDir)
{
WIN32_FIND_DATA fdFile;
HANDLE hFind = NULL;
wchar_t sPath[2048];
//Specify a file mask. *.* = We want everything!
wsprintf(sPath, L"%s\\*.*", sDir);
if((hFind = FindFirstFile(sPath, &fdFile)) == INVALID_HANDLE_VALUE)
{
wprintf(L"Path not found: [%s]\n", sDir);
return false;
}
do
{
//Find first file will always return "."
// and ".." as the first two directories.
if(wcscmp(fdFile.cFileName, L".") != 0
&& wcscmp(fdFile.cFileName, L"..") != 0)
{
//Build up our file path using the passed in
// [sDir] and the file/foldername we just found:
wsprintf(sPath, L"%s\\%s", sDir, fdFile.cFileName);
//Is the entity a File or Folder?
if(fdFile.dwFileAttributes &FILE_ATTRIBUTE_DIRECTORY)
{
wprintf(L"Directory: %s\n", sPath);
ListDirectoryContents(sPath); //Recursion, I love it!
}
else{
wprintf(L"File: %s\n", sPath);
}
}
}
while(FindNextFile(hFind, &fdFile)); //Find the next file.
FindClose(hFind); //Always, Always, clean things up!
return true;
}
網上的都是類似的,還有說遍歷複雜云云,其實不復雜,程式碼短並且省記憶體(這裡主要是省棧),速度更快。
這樣寫的時候,想想就發現,有兩個地方可以優化,第一,區域性變數sPath,這裡佔用記憶體大,而且還每次都複製一次,速度慢;第二、區域性變數fdFile,這個佔用記憶體也大......
又大又慢,所以會爆棧。
我現在記事本寫一個比這個好的(N年前就這麼寫了,還有牛人說不需要遞迴,當時想了一下,我也實現了)。
UINT ListFiles(const TCHAR *pathname, UINT pathnamelength, UINT pathnamesize, WIN32_FIND_DATA *pfd)
{
HANDLE hfind;
UINT l;
UINT result = 0;
if (pathnamelength > 0 && pathname[pathnamelength - 1] != _T('\\'))
{
pathname[pathnamelength++] = _T('\\');
}
pathname[pathnamelength+0] = _T('*');
pathname[pathnamelength+1] = _T('.');
pathname[pathnamelength+2] = _T('*');
pathname[pathnamelength+3] = _T('\0');
if(hfind != INVALID_HANDLE_VALUE)
{
do
{
// 這裡可以優化的,留給有追求的人優化,不過這裡不是關鍵
if(_tcscmp(pfd->cFileName, _T(".")) != 0 && _tcscmp(pfd->cFileName, _T("..")) != 0)
{
l = _tcslen(pfd->cFileName);
// 避免越界
if (pathnamelength + l < pathnamesize)
{
// 重用了佔用記憶體的pathname和pfd
_tcscpy(pathname + pathnamelength, pfd->cFileName);
// 已經獲取了檔案資訊,愛幹嘛幹嘛去
if(pfd->dwFileAttributes &FILE_ATTRIBUTE_DIRECTORY)
{result += ListFiles(pathname, pathnamelength + l, pathnamesize, pfd);
}
else{
result++;
}
}
} while(FindNextFile(hfind, pfd));
FindClose(hfind);
}
return (result);
}
我在網上看到linux下遍歷的程式碼也大同小異,也沒有優化,都可以類似這麼寫的。
不驕傲,一個小程式碼而已,N年前就會這麼寫了。