0

我正在寻找一个跨平台函数,它支持目录内容的通配符列表,类似于 Windows 上的 FindFirstFile。

windows 中接受的通配符模式是否非常特定于 windows?我想要一些支持 FindFirstFile 通配符模式的东西,但他也在 Linux 中工作。

4

2 回答 2

2

如果 C++17 及更高版本:您可以使用目录迭代器“遍历”目录,并将遍历的文件名与正则表达式匹配,如下所示:

static std::optional<std::string> find_file(const std::string& search_path, const std::regex& regex) {
    const std::filesystem::directory_iterator end;
    try {
        for (std::filesystem::directory_iterator iter{search_path}; iter != end; iter++) {
            const std::string file_ext = iter->path().extension().string();
            if (std::filesystem::is_regular_file(*iter)) {
                if (std::regex_match(file_ext, regex)) {
                    return (iter->path().string());
                }
            }
        }
    }
    catch (std::exception&) {}
    return std::nullopt;
}

例如,用于查找以 .txt 结尾的第一个文件:

auto first_file = find_file("DocumentsDirectory", std::regex("\\.(?:txt)"));

同样,如果您感兴趣的不仅仅是通过扩展匹配,功能行

const std::string file_ext = iter->path().extension().string();

应该修改为捕获您感兴趣的文件名部分(或文件的整个路径)的内容

然后可以在一个函数中使用它,该函数按目录执行通配符列表。

于 2020-05-22T17:16:24.577 回答
0

这是一个递归变体。

它为列表中的每个文件调用一个函数f并返回找到的文件数。它也是递归的:它将子目录下降到指定的最大深度。请注意,搜索过滤器会匹配文件名。

删除了 try-catch 块,以便调用者可以捕获和处理任何问题。

#include <string>
#include <regex>
#include <filesystem>

// recursively call a functional *f* for each file that matches the expression
inline int foreach_file(const std::string& search_path, const std::regex& regex, int depth, std::function<void(std::string)> f) {
    int n = 0;
    const std::filesystem::directory_iterator end;
    for (std::filesystem::directory_iterator iter{ search_path }; iter != end; iter++) {
        const std::string filename = iter->path().filename().string();
        if (std::filesystem::is_regular_file(*iter)) {
            if (std::regex_match(filename, regex)) {
                n++;
                f(iter->path().string());
            }
        }
        else if (std::filesystem::is_directory(*iter) && depth>0) {
            n += foreach_file(iter->path().string(), regex, depth - 1, f);
        }
    }
    return n;
}

例子:


void do_something(string filename) {
...
}


void do_all_json_that_start_with_z() {
    // regex matches the whole filename 
    regex r("z.*.json", regex::ECMAScript | regex::icase); // ignoring case
    foreach_file(R"(C:\MyFiles\)", r, 99, do_something); // max depth 99
}

// can use lambdas
void do_all_json_that_start_with_z() {
    int n=0;
    foreach_file(
        R"(C:\MyFiles\)", // using raw string - for windows
        regex("z.*.json"),
        0,                // do not descend to sub-directories 
        [&n](string s) { printf("%d) %s\n", ++n, s.c_str()); });
}



于 2022-02-01T10:21:19.460 回答