使用FindFirstFile和FindNextFile

时间:2017-08-10 08:22:28

标签: c++ windows winapi recursion wildcard

我有一个工作代码,它返回给定带外卡目录的所有子目录中的所有文件。例如:"C://*"。这完全没问题。现在,我想知道是否可以使用特定的文件扩展名递归迭代所有文件。例如:"C://*.png",而不更改代码。我一直在寻找...... "C://*/../*.png",但我找不到解决办法。我可以使用任何通配符技巧吗?

2 个答案:

答案 0 :(得分: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来搜索所有子目录。

答案 1 :(得分:0)

这是一个使用 FindFirstFile FindNextFile 的示例,可以递归查找具有给定扩展名的文件。

#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或控制台应用程序中使用它们没有问题。