2017-08-10 134 views
0

我有一個工作代碼,它返回給定目錄下所有子目錄中的所有文件並使用通配符。例如:"C://*"。這工作非常好。現在,我想知道是否可以使用某個文件擴展名遞歸地迭代所有文件。例如:"C://*.png",而不更改代碼。我正在尋找像:"C://*/../*.png",但我找不到解決方案。我可以使用任何通配技巧嗎?使用FindFirstFile和FindNextFile遞歸地查找具有特定擴展名的文件

+1

從文檔:_「目錄或路徑以及文件名。文件名可以包含通配符,例如__an__星號(*)或__a__問號(?)。」_ https:// msdn .microsoft.com/en-us/library/windows/desktop/aa364418(v = vs.85).aspx –

+0

是的,我已經看到了。你想說什麼? @RichardCritten – thigi

+0

這真的沒有太大的幫助。所以我想這沒有解決辦法? @RichardCritten – thigi

回答

1

您需要遞歸搜索每個子目錄。我碰巧有一些代碼可以做到這一點,下面的代碼可能會有所幫助。

#include <functional> 
#include <io.h> 

enum enumflags { 
    ENUM_FILE = 1, 
    ENUM_DIR, 
    ENUM_BOTH 
}; 


//return value: 
// False means that the searching has been aborted by the callback function. 
// It will return true otherwise. 
bool enumsubfiles(

    const std::wstring &dir_with_back_slant,  //for example: L"C:\\", L"E:\\test\\" 
    const std::wstring &filename,     //for example: L"123.txt", L"*.exe", L"123.???" 
    unsigned int maxdepth,     //0 means not searching subdirectories, 1 means maximum depth of subdirectories is 1, 
              // pass -1 to search all the subdirectories. 
    enumflags flags,      //search files, directories, or both. 
    std::function<bool(const std::wstring &dir_with_back_slant, _wfinddata_t &attrib)> callback 
) 
{ 
    _wfinddata_t dat; 
    size_t hfile; 
    std::wstring fullname = dir_with_back_slant + filename; 
    std::wstring tmp; 
    bool ret = true; 


    hfile = _wfindfirst(fullname.c_str(), &dat); 
    if (hfile == -1) goto a; 
    do { 
     if (!(wcscmp(L".", dat.name) && wcscmp(L"..", dat.name))) continue; 
     if (((dat.attrib&_A_SUBDIR) && (!(flags&ENUM_DIR))) || ((!(dat.attrib&_A_SUBDIR)) && (!(flags&ENUM_FILE)))) continue; 
     ret = callback(dir_with_back_slant, dat); 
     if (!ret) { 
      _findclose(hfile); 
      return ret; 
     } 
    } while (_wfindnext(hfile, &dat) == 0); 
    _findclose(hfile); 

a: 

    if (!maxdepth) return ret; 

    tmp = dir_with_back_slant + L"*"; 
    hfile = _wfindfirst(tmp.c_str(), &dat); 
    if (hfile == -1) return ret; 
    do { 
     if (!(wcscmp(L".", dat.name) && wcscmp(L"..", dat.name))) continue; 
     if (!(dat.attrib&_A_SUBDIR)) continue; 
     tmp = dir_with_back_slant + dat.name + L"\\"; 
     ret = enumsubfiles(tmp, filename, maxdepth - 1, flags, callback); 
     if (!ret) { 
      _findclose(hfile); 
      return ret; 
     } 


    } while (_wfindnext(hfile, &dat) == 0); 
    _findclose(hfile); 

    return ret; 

} 

這裏是上述函數的用法示例:

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    using namespace std; 

    //the default code page of my console window is 936 
    setlocale(CP_ACP, ".936"); 

    enumsubfiles(L"C:\\", L"*.exe", 1, ENUM_FILE, [](const std::wstring &dir_with_back_slant, _wfinddata_t &attrib)->bool 
    { 
     std::wcout << dir_with_back_slant << attrib.name << '\n'; 
     return true;   //return true to continue, return false to abort searching. 
    }); 

    return 0; 
} 

,你會得到下面的輸出:

C:\OpenSSL-Win64\unins000.exe 
C:\putty\PAGEANT.EXE 
C:\putty\PLINK.EXE 
C:\putty\PSCP.EXE 
C:\putty\PSFTP.EXE 
C:\putty\PUTTY.EXE 
C:\putty\PUTTYGEN.EXE 
C:\Windows\ampa.exe 
C:\Windows\bfsvc.exe 
C:\Windows\explorer.exe 
C:\Windows\HelpPane.exe 
C:\Windows\hh.exe 
C:\Windows\notepad.exe 
C:\Windows\regedit.exe 
C:\Windows\RtCRU64.exe 
C:\Windows\SECOH-QAD.exe 
C:\Windows\splwow64.exe 
C:\Windows\winhlp32.exe 
C:\Windows\write.exe 
C:\測試\測試.exe 

的MAXDEPTH我傳遞給函數爲1 。傳遞-1以搜索所有子目錄。

+0

NTFS和Windows API都支持Unicode。你提出的答案不是。 – IInspectable

+0

@IInspectable謝謝你的建議!該代碼已被修改爲支持Unicode – liuqx

0

這裏是使用用FindFirstFileFindNextFile唯一可以遞歸找到具有給定擴展名的文件的例子。

#include "stdafx.h" 
#include <Windows.h> 
#include <atlpath.h> 
#include <list> 
#include <iostream> 

#ifdef _UNICODE 
#define cout wcout 
#endif 

void FindFiles(
    const CString& strRootPath, 
    const CString& strExt, 
    std::list<CString>& listFiles, 
    bool bRecursive = true) 
{ 
    CString strFileToFind = strRootPath; 
    ATLPath::Append(CStrBuf(strFileToFind, MAX_PATH), _T("*.*")); 

    WIN32_FIND_DATA findData = { 0 }; 
    HANDLE hFileFind = ::FindFirstFile(strFileToFind, &findData); 
    if (INVALID_HANDLE_VALUE != hFileFind) 
    { 
     do 
     { 
      CString strFileName = findData.cFileName; 
      if ((strFileName == _T(".")) || (strFileName == _T(".."))) 
       continue; 

      CString strFilePath = strRootPath; 
      ATLPath::Append(CStrBuf(strFilePath, MAX_PATH), strFileName); 
      if (bRecursive && (ATLPath::IsDirectory(strFilePath))) 
      { 
       FindFiles(strFilePath, strExt, listFiles); 
      } 
      else 
      { 
       CString strFoundExt = ATLPath::FindExtension(strFilePath); 
       if (! strExt.CompareNoCase(strFoundExt)) 
        istFiles.push_back(strFilePath); 
      } 

     } while (::FindNextFile(hFileFind, &findData)); 

     ::FindClose(hFileFind); 
    } 
} 

int main() 
{ 
    std::list<CString> listFiles; 
    FindFiles(_T("e:\\tests"), _T(".cpp"), listFiles); 
    for (const auto& strFile : listFiles) 
     std::cout << strFile.GetString() << std::endl; 

    return 0; 
} 

注:爲了方便起見,我用ATL的東西像ATL :: CString的和ATLPath功能。在Win32或控制檯應用程序中使用它們沒有任何問題。

相關問題