如何轻松地从包含通配符的路径中获取所有文件路径?例如:C:/Data * Set/Files */*。txt,我在Linux上使用glob函数编写了它,但在Windows:/上却做不到。

不幸的是,FindFirstFile在目录名称中不支持通配符。

我认为应该有Windows解决方案可用,但找不到。

最佳答案

因此,您应该放弃使用特定于操作系统的文件访问,而应该使用独立于操作系统的文件:Filesystem Library

假设您获得了filesystem::path input,其中包含带有通配符的路径。要使用它来解决您的问题,您需要:

  • 使用 parent_path input分解为目录
  • 使用 filename 获取input文件名
  • 获取 directory_iterator input开始的相对或绝对路径
  • 创建一个递归函数,该函数将beginend迭代器引入到获取的父路径,目录迭代器和文件名
  • 每当目录或文件名使用'*'时,请使用带有迭代器的regex来确定应前进到下一个
  • 的目录
  • 返回匹配文件的路径或一个空的path

  • 由于the excellent Ben Voigt's comment,我已经更新了算法以遍历未通配的目录。

    例如:
    regex GenerateRegex(string& arg) {
        for (auto i = arg.find('*'); i != string::npos; i = arg.find('*', i + 2)) {
            arg.insert(i, 1, '.');
        }
    
        return regex(arg);
    }
    
    filesystem::path FindFirstFile(filesystem::path directory, filesystem::path::const_iterator& start, const filesystem::path::const_iterator& finish, string& filename) {
        while (start != finish && start->string().find('*') == string::npos) {
            directory /= *start++;
        }
        filesystem::directory_iterator it(directory);
        filesystem::path result;
    
        if (it != filesystem::directory_iterator()) {
            if (start == finish) {
                for (auto i = filename.find('.'); i != string::npos; i = filename.find('.', i + 2)) {
                    filename.insert(i, 1, '\\');
                }
                const auto re = GenerateRegex(filename);
    
                do {
                    if (!filesystem::is_directory(it->status()) && regex_match(it->path().string(), re)) {
                        result = *it;
                        break;
                    }
                } while (++it != filesystem::directory_iterator());
            }
            else {
                const auto re = GenerateRegex(start->string());
    
                do {
                    if (it->is_directory() && regex_match(prev(it->path().end())->string(), re)) {
                        result = FindFirstFile(it->path(), next(start), finish, filename);
    
                        if (!result.empty()) {
                            break;
                        }
                    }
                } while (++it != filesystem::directory_iterator());
            }
        }
        return result;
    }
    

    可以通过以下方式调用:
    const filesystem::path input("C:/Test/Data*Set/Files*/*.txt");
    
    if (input.is_absolute()) {
        const auto relative_parent = input.parent_path().relative_path();
    
        cout << FindFirstFile(input.root_path(), begin(relative_parent), end(relative_parent), input.filename().string()) << endl;
    } else {
        const auto parent = input.parent_path();
    
        cout << FindFirstFile(filesystem::current_path(), begin(parent), end(parent), input.filename().string()) << endl;
    }
    

    09-10 03:50
    查看更多