我正在寻找一个跨平台函数,它支持目录内容的通配符列表,类似于 Windows 上的 FindFirstFile。
windows 中接受的通配符模式是否非常特定于 windows?我想要一些支持 FindFirstFile 通配符模式的东西,但他也在 Linux 中工作。
我正在寻找一个跨平台函数,它支持目录内容的通配符列表,类似于 Windows 上的 FindFirstFile。
windows 中接受的通配符模式是否非常特定于 windows?我想要一些支持 FindFirstFile 通配符模式的东西,但他也在 Linux 中工作。
如果 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();
应该修改为捕获您感兴趣的文件名部分(或文件的整个路径)的内容
然后可以在一个函数中使用它,该函数按目录执行通配符列表。
这是一个递归变体。
它为列表中的每个文件调用一个函数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()); });
}