Home > Software engineering >  Get FullPath of a given filename in C
Get FullPath of a given filename in C

Time:09-21

Hi I want to get the full file path of a given filename Ex. string a = "sample.txt" and it will basically search for any sample.txt on drive c:\ and if it was found, I want to output the fullpath ex. C:\Users\windows10\desktop\sample.txt

any thought on how to do that?

Note: I highly appreciate it there's no boost::filesystem involved

CodePudding user response:

In C 17 and above you can use std::filesystem in a OS independent way, which is better than just aiming for Windows (imo).

It can be done in many ways, but I have include a solution that utilise recursion and looks at the file path. As you can see, I base it on string comparison, so if you want to it can be adopted to using partial name matching using string contains in C 23.

#include <string>
#include <vector>

#include <filesystem>

#include <iostream>

std::vector<std::string> get_file_paths(const std::string dir, const std::string& file_name)
{
    std::cout << "Looking for files in: " << dir << "\n";
    std::vector<std::string> files;
    
    for (auto const& dir_entry : std::filesystem::directory_iterator(std::filesystem::path(dir)))
    {
        if (std::filesystem::is_directory(dir_entry.path()))
        {
            auto sub_files = get_file_paths(dir_entry.path().string(), file_name);
            files.insert(files.end(), sub_files.begin(), sub_files.end()); 
        }
        else
        {
            if (dir_entry.path().filename() == file_name)
            {
                files.emplace_back(dir_entry.path().string()); 
            }
        }
    }
    return files; 
}

int main(int argc, char *argv[])
{
    (void) argc; 
    auto start_directory = std::string(argv[1]);
    auto file_name = std::string(argv[2]);

    std::cout << "Finding files with name " << file_name << " starting from directory " << start_directory << "\n";
    auto files = get_file_paths(start_directory, file_name);
    std::cout << "\n\nFound files: \n";
    for (const auto& file : files)
    {
        std::cout << file << "\n";
    }
} 

CodePudding user response:

For Win32, you'd do this operation with recursion and the FindFirstFileExW / FindNextFileW operations.

This sample code is for taking paths with wildcards and finding the path of the matches.

#include <Windows.h>

#include <cstdlib>
#include <cwchar>
#include <list>
#include <memory>
#include <string>

namespace
{
    inline HANDLE safe_handle(HANDLE h) noexcept { return (h == INVALID_HANDLE_VALUE) ? nullptr : h; }

    struct find_closer { void operator()(HANDLE h) noexcept { assert(h != INVALID_HANDLE_VALUE); if (h) FindClose(h); } };

    using ScopedFindHandle = std::unique_ptr<void, find_closer>;
}

    void SearchForFiles(const wchar_t* path, std::list<std::wstring>& files, bool recursive)
    {
        // Process files
        WIN32_FIND_DATAW findData = {};
        ScopedFindHandle hFile(safe_handle(FindFirstFileExW(path,
            FindExInfoBasic, &findData,
            FindExSearchNameMatch, nullptr,
            FIND_FIRST_EX_LARGE_FETCH)));
        if (hFile)
        {
            for (;;)
            {
                if (!(findData.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY)))
                {
                    wchar_t drive[_MAX_DRIVE] = {};
                    wchar_t dir[_MAX_DIR] = {};
                    _wsplitpath_s(path, drive, _MAX_DRIVE, dir, _MAX_DIR, nullptr, 0, nullptr, 0);

                    SConversion conv = {};
                    wchar_t fp[_MAX_PATH] = {};
                    _wmakepath_s(fp, drive, dir, findData.cFileName, nullptr);
                    files.push_back(fp);
                }

                if (!FindNextFileW(hFile.get(), &findData))
                    break;
            }
        }

        // Process directories
        if (recursive)
        {
            wchar_t searchDir[MAX_PATH] = {};
            {
                wchar_t drive[_MAX_DRIVE] = {};
                wchar_t dir[_MAX_DIR] = {};
                _wsplitpath_s(path, drive, _MAX_DRIVE, dir, _MAX_DIR, nullptr, 0, nullptr, 0);
                _wmakepath_s(searchDir, drive, dir, L"*", nullptr);
            }

            hFile.reset(safe_handle(FindFirstFileExW(searchDir,
                FindExInfoBasic, &findData,
                FindExSearchLimitToDirectories, nullptr,
                FIND_FIRST_EX_LARGE_FETCH)));
            if (!hFile)
                return;

            for (;;)
            {
                if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
                {
                    if (findData.cFileName[0] != L'.')
                    {
                        wchar_t subdir[MAX_PATH] = {};

                        {
                            wchar_t drive[_MAX_DRIVE] = {};
                            wchar_t dir[_MAX_DIR] = {};
                            wchar_t fname[_MAX_FNAME] = {};
                            wchar_t ext[_MAX_FNAME] = {};
                            _wsplitpath_s(path, drive, dir, fname, ext);
                            wcscat_s(dir, findData.cFileName);
                            _wmakepath_s(subdir, drive, dir, fname, ext);
                        }

                        SearchForFiles(subdir, files, recursive);
                    }
                }

                if (!FindNextFileW(hFile.get(), &findData))
                    break;
            }
        }
    }
  • Related