【问题标题】:Recursive function for listing all files in sub directories列出子目录中所有文件的递归函数
【发布时间】:2012-10-29 20:43:52
【问题描述】:

我正在尝试编写一个函数,该函数返回当前文件夹及其所有子文件夹中所有文件的列表。我写了这段代码:

#include <iostream>
#include <dirent.h>
#include <cstring>

using namespace std;

int main() {
   DIR* dir; dirent* pdir;
   //From my workspace
   dir=opendir(".");     
   while (pdir=readdir(dir)) {
       if(/**********This pdir is a directory**********/) {
           /**********RECURSIVE CALL SHOULD BE HERE**********/
           cout<<pdir->d_name<<endl;
       }
   }
   closedir(dir);
   return 0;
}

我在谷歌上搜索过,但我不知道如何:

  • 检查当前pdir是否为目录
  • 进入目录并对其执行递归调用

与此同时,我在 main 上拥有一切,因为我仍然不知道递归函数应该有哪些参数。

有什么提示吗?

【问题讨论】:

标签: c++


【解决方案1】:

这是使用建议的标准文件系统库的版本:

#include <iostream>
#include <filesystem>

using namespace std;
using namespace std::tr2::sys;

void main()
{   
  for (recursive_directory_iterator i("."), end; i != end; ++i) 
    if (!is_directory(i->path()))
      cout << i->path().filename() << "\n";
} 

【讨论】:

    【解决方案2】:

    除非您的目标是学习如何编写递归函数,否则您可能更喜欢这个基于Boost.Filesystem 的简单循环:

    #include "boost/filesystem.hpp"
    #include <iostream>
    
    int main () {
      for ( boost::filesystem::recursive_directory_iterator end, dir("./");
        dir != end; ++dir ) {
        // std::cout << *dir << "\n";  // full path
        std::cout << dir->path().filename() << "\n"; // just last bit
      }
    }
    

    甚至是单个函数调用:

    std::copy(
      boost::filesystem::recursive_directory_iterator("./"),
      boost::filesystem::recursive_directory_iterator(),
      std::ostream_iterator<boost::filesystem::directory_entry>(std::cout, "\n"));
    

    【讨论】:

    • 您的示例的一个小问题是它列出了除文件之外的目录 - 请参阅我对排除目录的回答。
    【解决方案3】:

    我在 C++11 中的方法:

    #include <string>
    #include <functional>
    #include <dirent.h>
    
    void listFiles(const std::string &path, std::function<void(const std::string &)> cb) {
        if (auto dir = opendir(path.c_str())) {
            while (auto f = readdir(dir)) {
                if (!f->d_name || f->d_name[0] == '.') continue;
                if (f->d_type == DT_DIR) 
                    listFiles(path + f->d_name + "/", cb);
    
                if (f->d_type == DT_REG)
                    cb(path + f->d_name);
            }
            closedir(dir);
        }
    }
    

    用法:

    listFiles("my_directory/", [](const std::string &path) {
        std::cout << path << std::endl;
    });
    

    【讨论】:

    • listFiles(path + f-&gt;d_name + "/", cb); 上的另一个错误:应该是 listFiles(path + "/" + f-&gt;d_name + "/", cb);
    【解决方案4】:

    将该代码隔离在以基目录路径为参数的过程中,这样您就可以实际执行递归调用。应该是这样的

    void recursive_file_list(const char * directory)
    {
        // ...
    }
    

    那么,要检查你得到的pdir是不是一个目录,你有两条路线:

    • 你可以检查pdir-&gt;d_type==DT_DIR;这会立即为您提供此信息,但它不可移植(POSIX 不要求存在 d_type 成员);此外,并非所有文件系统都支持它,因此您可能会得到DT_UNKNOWN。如果你想遵循符号链接,如果你得到DT_LNK,你也必须执行额外的检查。在这些情况下,您必须回退到 lstat(请参阅以下几点);
    • 您可以改为使用 lstat 获取有关每个文件的信息,特别是检查 struct statst_mode 字段。

    【讨论】:

    • 即使d_type 存在,您也必须回退到stat,因为即使操作系统支持,文件系统也不需要填写d_type。此外,d_type 的值不是 位掩码,您只需要(pdir-&gt;d_type == DT_DIR)
    【解决方案5】:

    使用 C++17 recursive_directory_iterator 变得简洁如下:

    void ls_recursive(const std::filesystem::path& path) {
        for(const auto& p: std::filesystem::recursive_directory_iterator(path)) {
            if (!std::filesystem::is_directory(p)) {
                std::cout << p.path() << '\n';
            }
        }
    }
    

    带有示例输出:

    "/home/user/prj/rust/stack/Cargo.toml"
    "/home/user/prj/rust/stack/.gitignore"
    "/home/user/prj/rust/stack/src/main.rs"
    "/home/user/prj/rust/stack/.git/config"
    

    【讨论】:

      【解决方案6】:

      它使用标准的 c++ 功能。无需在代码中包含任何第三方库。

      只发送目录路径作为参数。它将还原该文件夹及其子文件夹中存在的每个文件路径。

      此外,如果您需要对任何特定类型的文件(即 .txt 或 .jpg)进行排序,传递扩展名,它将打印所有具有相应扩展名的文件路径。

      #include <Windows.h>
      #include<iostream>
      #include<vector>
      #include<string>
      using namespace std;
      
      vector<string> files;
      
      std::string Recursive(std::string folder) {
          std::string search_path = folder + "/*.*";
          WIN32_FIND_DATA fd;
          HANDLE hFind = ::FindFirstFile(search_path.c_str(), &fd);
          std::string tmp;
          if (hFind != INVALID_HANDLE_VALUE) {
              do {
                  if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
                      if (!(!strcmp(fd.cFileName, ".") || !strcmp(fd.cFileName, ".."))) {
                          tmp = folder + "\\";
                          tmp = tmp + fd.cFileName;
                          Recursive(tmp);
                      }
                  }
                  else {
                      std::string FinalFilePath = folder + "\\" + fd.cFileName;
                      files.push_back(FinalFilePath);
                  }
      
              } while (::FindNextFile(hFind, &fd));
              ::FindClose(hFind);
          }
          return folder;
      }
      
      bool has_suffix(const std::string& str, const std::string& suffix) {
          return str.size() >= suffix.size() &&
              str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
      }
      
      int main(){
      std::string folder = "C:\\Users\\Omkar\\Desktop\\Test";
          Recursive(folder);
          std::string t;
          const auto needle = std::string(".txt");
          while (!files.empty()) {
              t = files.back();
              if (has_suffix(t, ".mmt")) {
                  cout << "FINAL PATH : " << t << endl;
                  t.clear();
              }
              files.pop_back();
          }
      return 0;
      }
      

      【讨论】:

        【解决方案7】:

        路径应该类似于/your_path/。要在隐藏文件夹中搜索,您应该添加第三个参数true

        #include <dirent.h>
        #include <vector>
        #include <cstring>    
        
        void GetReqDirs(const std::string& path, std::vector<string>& files,const bool showHiddenDirs = false){
            DIR *dpdf;
            struct dirent *epdf;
            dpdf = opendir(path.c_str());
            if (dpdf != NULL){
                while ((epdf = readdir(dpdf)) != NULL){
                    if(showHiddenDirs ? (epdf->d_type==DT_DIR && string(epdf->d_name) != ".." && string(epdf->d_name) != "." ) : (epdf->d_type==DT_DIR && strstr(epdf->d_name,"..") == NULL && strstr(epdf->d_name,".") == NULL ) ){
                        GetReqDirs(path+epdf->d_name+"/",files, showHiddenDirs);
                    }
                    if(epdf->d_type==DT_REG){
                        files.push_back(path+epdf->d_name);
                    }
                }
            }
            closedir(dpdf);
        }
        

        【讨论】:

          【解决方案8】:

          您可以检查是否没有“。”在字符串中。

          if(strstr(pdir->d_name,".") != NULL)
          

          【讨论】:

          • . 是一个完美的目录名称部分。
          【解决方案9】:

          这是我的使用方法

          std::vector<std::string> get_all_files_recursive(const fs::path& path)
              {
                  std::vector<std::string> result;
          
                  for (const auto& p : fs::recursive_directory_iterator(path))
                  {
                      if (!fs::is_directory(p))
                      {
                          fs::path path = p.path();
                          result.push_back(path.u8string());
                      }
                  }
          
                  return result;
              }
          

          【讨论】:

            猜你喜欢
            • 2010-10-19
            • 2020-08-19
            • 2014-09-07
            • 1970-01-01
            • 2010-10-04
            • 2010-10-30
            • 1970-01-01
            • 2016-06-06
            • 1970-01-01
            相关资源
            最近更新 更多