Three Ways to Find Files

Let’ say we have to implement a function that search a folder to recursively find files having an extension from a given list of extensions. This article shows three possible implementations: one using FindFirstFile and FindNextFile WinAPI functions, one using CFileFind MFC class and one using Filesystem Library.

Find files using FindFirstFile and FindNextFile WinAPI functions

Althugh this implementation uses some ATL stuff to make things easier, it appears still quite complicated.

void demo::FindFiles(const CString& strRootPath,       // initial path to search
                     const std::list<CString> listExt, // a list of file extensions
                     std::list<CString>& listFiles)    // output list of files found
{
    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 (ATLPath::IsDirectory(strFilePath))
            {
                // call recursive
                FindFiles(strFilePath, listExt, listFiles);
            }
            else
            {
                CString strExt = ATLPath::FindExtension(strFilePath);
                strExt.TrimLeft(_T('.'));

                if (IsStringInListNoCase(strExt, listExt))
                {
                    listFiles.push_back(strFilePath);
                }
            }

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

        ::FindClose(hFileFind);
    }
}

Find files using CFileFind MFC class

Using CFileFind MFC class can make code a little bit shorter and the programmer’s life easier.

void demo::FindFiles(const CString& strRootPath,
                     const std::list<CString> listExt,
                     std::list<CString>& listFiles)
{
    CString strFileToFind = strRootPath + _T("\\*.*");

    CFileFind fileFind;
    BOOL bMoreFiles = fileFind.FindFile(strFileToFind);
    while (bMoreFiles)
    {
        bMoreFiles = fileFind.FindNextFile();
        if (fileFind.IsDots())
            continue;

        CString strFilePath = fileFind.GetFilePath();
        if (fileFind.IsDirectory())
        {
            // call recursive
            FindFiles(strFilePath, listExt, listFiles);
        }
        else
        {
            int nPos = strFilePath.ReverseFind(_T('.'));
            if (-1 != nPos)
            {
                CString strExt = strFilePath.Right(strFilePath.GetLength() - nPos - 1);
                if (IsStringInListNoCase(strExt, listExt))
                {
                    listFiles.push_back(strFilePath);
                }
            }
        }
    }
}

Note: IsStringInListNoCase searches a list for a string, not case sensitive. You can find its implementation in the attached demo solution.

Find files using Filesystem Library

Here it is:

void demo::FindFiles(const CString& strRootPath,       // initial path to search
                     const std::list<CString> listExt, // a list of file extensions
                     std::list<CString>& listFiles)    // output list of files found
{
    _FSPFX path root_path(strRootPath.GetString());
    _FSPFX recursive_directory_iterator end;
    _FSPFX recursive_directory_iterator iter(root_path);
    while (iter != end)
    {
        const auto& path = iter->path();
        CString strExt = path.extension().c_str();
        strExt.TrimLeft(_T('.'));
        if (IsStringInListNoCase(strExt, listExt))
        {
            listFiles.push_back(path.c_str());
        }
        ++iter;
    }
}

Hurray, we did it in just few lines of code! 🙂
Of course, it can be used in MFC, ATL, Win32 and Console applications, as well.

Demo solution

Download: Find-Files-Samples.zip

The demo solution contains three projects, each having one of the above implementations.

Resources and related articles