2

I need to find a fews file based on a pattern: C:\Users\Admin\Desktop\*\cities.json and countries.json. Basically it is on the Desktop, but it can be in any folder there.

I found a similar function posted by Thomas Bonini. I don't really need the linux part. How can I do that?

/* Returns a list of files in a directory (except the ones that begin with a dot) */

void GetFilesInDirectory(std::vector<string> &out, const string &directory)
{
    HANDLE dir;
    WIN32_FIND_DATA file_data;

    if ((dir = FindFirstFile((directory + "/*").c_str(), &file_data)) == INVALID_HANDLE_VALUE)
        return; /* No files found */

    do {
        const string file_name = file_data.cFileName;
        const string full_file_name = directory + "/" + file_name;
        const bool is_directory = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;

        if (file_name[0] == '.')
            continue;

        if (is_directory)
            continue;

        out.push_back(full_file_name);
    } while (FindNextFile(dir, &file_data));

    FindClose(dir);
} // GetFilesInDirectory

Edit:

Based on @Someprogrammerdude's comment. It works well, but both of these files should be in a same folder. For ex. If cities.json is presented but countries.json is not in the directory, then it should be ignored. How do I perform that check as well?

std::vector<std::filesystem::path> test()
{
    auto vec{ std::vector<std::filesystem::path> {} };
    
    for (const auto& entry : std::filesystem::recursive_directory_iterator(L"C:\\Users\\Admin\\Desktop\\"))
    {
        if (entry.is_regular_file())
        {
            const auto& full_path = entry.path();

            if (const auto filename = entry.path().filename(); filename == L"countries.json" || filename == L"cities.json")
            {
                vec.push_back(full_path);
            }
        }
    }

    return vec;
}
nop
  • 4,711
  • 6
  • 32
  • 93
  • ... remove the entire #else section? or just keep it. Personally I would just use the standard `filesystem` library – Botje Jun 23 '21 at 11:34
  • Use [`std::filesystem::recursive_directory_iterator`](https://en.cppreference.com/w/cpp/filesystem/recursive_directory_iterator) to find the files you need. – Some programmer dude Jun 23 '21 at 11:35
  • Thank you guys! @Someprogrammerdude, look at what I did. Edited the question. How do I check if both of these files are presented in that directory? – nop Jun 23 '21 at 12:13
  • @nop Change `||` to `&&`? – 김선달 Jun 23 '21 at 13:55
  • You need to make sure that the [parent path](https://en.cppreference.com/w/cpp/filesystem/path/parent_path) of both files are the same. – Some programmer dude Jun 23 '21 at 14:03

1 Answers1

1

You need to check recursively (like in merge-sort, for example) if the elements of a directory contains the names of the vector, and if it contains all of them return the vector or in case a recursion returned a match forward that instead.

#include <filesystem>
#include <iostream>
#include <string>
#include <vector>

std::vector<std::filesystem::path> Find_Paird_Files
    (const std::wstring &root, const std::vector<std::wstring> &files){

    auto ret = std::vector<std::filesystem::path> {};
    auto sub = std::vector<std::filesystem::path> {};

    for (const auto & entry : std::filesystem::directory_iterator(root)) {
        if (entry.is_regular_file()) {
            for (const auto & name : files) {

                if (std::wcscmp(entry.path().filename().generic_wstring().c_str(), name.c_str()) == 0){
                    ret.push_back(entry.path());
                }
            }      
        }
        if (entry.is_directory()){
            sub = Find_Paird_Files(entry.path().generic_wstring(), files);
        }
        if (sub.size() == files.size()){
           goto return_branch;
        }
    }
    if (ret.size() != files.size()){
        ret.clear();
    }
    return ret;
    return_branch:
    return sub;
}

int main() {

    auto paths = Find_Paird_Files(
        L"D:\\Escritorio\\tmp_cpp", 
        {L"rules.ninja", L"build.ninja"}
    );

    for (const std::wstring & path : paths){
        std::wcout << path << std::endl;
    }

    return 0;
}
SrPanda
  • 854
  • 1
  • 5
  • 9
  • Thank you, it worked! You could change the vector in parameters to const reference `const std::vector&` in order to prevent copying. Also the `goto` => `ret sub`. – nop Jun 23 '21 at 18:36
  • The `goto` is more preference, i like to keep all the returns at the end of the function. – SrPanda Jun 23 '21 at 18:38
  • filesystem is only present from C++17 (gcc 5), doesn't work for centos 7 – Alexis May 26 '23 at 03:45
  • `Find_Paird_Files` was made with C++17 in mind, if you can't upgrade to support `std::filesystem`, you will need to implement that function with the native calls. – SrPanda May 26 '23 at 11:41