【问题标题】:Simple glob in C++ on unix system?Unix系统上C++中的简单glob?
【发布时间】:2012-01-14 03:57:51
【问题描述】:

我想在vector<string> 中检索遵循此模式的所有匹配路径:

"/some/path/img*.png"

我怎样才能简单地做到这一点?

【问题讨论】:

    标签: c++ unix glob


    【解决方案1】:

    对于 C++17 标准的较新代码,存在 std::filesystem,它可以通过 std::filesystem::directory_iterator 和递归版本实现这一点。您将不得不手动实现模式匹配。例如,C++11 regex 库。这将可移植到任何支持 C++17 的平台。

    std::filesystem::path folder("/some/path/");
    if(!std::filesystem::is_directory(folder))
    {
        throw std::runtime_error(folder.string() + " is not a folder");
    }
    std::vector<std::string> file_list;
    
    for (const auto& entry : std::filesystem::directory_iterator(folder))
    {
        const auto full_name = entry.path().string();
    
        if (entry.is_regular_file())
        {
           const auto base_name = entry.path().filename().string();
           /* Match the file, probably std::regex_match.. */
           if(match)
                file_list.push_back(full_name);
        }
    }
    return file_list;
    

    在非 C++17 案例的 boost 中也实现了类似的 API。 std::string::compare() 可能足以找到匹配项,包括多个调用,lenpos 参数仅匹配子字符串。

    【讨论】:

      【解决方案2】:

      我的要点是。我在 glob 周围创建了一个 stl 包装器,以便它返回字符串向量并负责释放 glob 结果。效率不是很高,但这段代码更易读,有些人会说更容易使用。

      #include <glob.h> // glob(), globfree()
      #include <string.h> // memset()
      #include <vector>
      #include <stdexcept>
      #include <string>
      #include <sstream>
      
      std::vector<std::string> glob(const std::string& pattern) {
          using namespace std;
      
          // glob struct resides on the stack
          glob_t glob_result;
          memset(&glob_result, 0, sizeof(glob_result));
      
          // do the glob operation
          int return_value = glob(pattern.c_str(), GLOB_TILDE, NULL, &glob_result);
          if(return_value != 0) {
              globfree(&glob_result);
              stringstream ss;
              ss << "glob() failed with return_value " << return_value << endl;
              throw std::runtime_error(ss.str());
          }
      
          // collect all the filenames into a std::list<std::string>
          vector<string> filenames;
          for(size_t i = 0; i < glob_result.gl_pathc; ++i) {
              filenames.push_back(string(glob_result.gl_pathv[i]));
          }
      
          // cleanup
          globfree(&glob_result);
      
          // done
          return filenames;
      }
      

      【讨论】:

      • 这不会检查任何错误,如果任何向量操作抛出,则会泄漏内存
      • @wakjah 我还注意到缺少错误检查(大禁忌)。所以我刚刚编辑了代码并保存了它。
      • glob.h 文件在哪里?
      • @chaohuang glob.h 是 unix/posix 系统上的系统头文件。它应该与其他标题(例如 stdio.h 等)位于同一位置。
      【解决方案3】:

      我在Centos6上试过上面的解决方案,发现需要改:

      int ret = glob(pat.c_str(), 0, globerr, &glob_result);
      

      (其中“globerr”是一个错误处理函数)

      没有明确的 0,我得到“GLOB_NOSPACE”错误。

      【讨论】:

        【解决方案4】:

        前段时间无聊时,我为 Windows 和 Linux 编写了一个简单的 glob 库(可能也适用于其他 *nixes),请随意使用它。

        示例用法:

        #include <iostream>
        #include "glob.h"
        
        int main(int argc, char **argv) {
          glob::Glob glob(argv[1]);
          while (glob) {
            std::cout << glob.GetFileName() << std::endl;
            glob.Next();
          }
        }
        

        【讨论】:

        • 如果有人使用构建系统并且包含使用 而不是 "",则此标头名称可能会在 Unix 系统上发生冲突
        【解决方案5】:

        您可以使用glob() POSIX 库函数。

        【讨论】:

        • glob() 是 POSIX 而不是 C99,它确实存在于任何现代 POSIX 兼容的 UNIX 发行版中。
        • 是的,没错。我真正想说的是,这是一个 C 风格的函数(产生 char** 而不是 std::vector&lt;std::string&gt; 等)。但它仍然是使用 C++ 编程时使用的正确函数。编写一个提供“C++ 风格”接口的包装器也应该相当容易。
        • 我认为 OP 想要 glob 一个字符串向量,从我可以看到 glob(3) 函数实际上在文件系统中查找...是否有任何库函数不访问文件系统——我也需要它。
        猜你喜欢
        • 2010-11-24
        • 1970-01-01
        • 1970-01-01
        • 2020-09-25
        • 1970-01-01
        • 2018-06-15
        • 2022-06-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多