简体   繁体   English

用于列出子目录中所有文件的递归函数

[英]Recursive function for listing all files in sub directories

I'm trying to write a function that returns a list of all files on current folder and all of its sub folders.我正在尝试编写一个函数,该函数返回当前文件夹及其所有子文件夹中所有文件的列表。 I wrote this code:我写了这段代码:

#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;
}

I searched for it in google and I don't know how to:我在谷歌搜索它,但我不知道如何:

  • Check if the current pdir is directory检查当前pdir是否为目录
  • Go inside the directory and perform the recursive call on it进入目录并对其执行递归调用

Meanwhile I have everything on main because I still don't know what arguments the recursive function should have.同时我把所有东西都放在 main 上,因为我仍然不知道递归函数应该有什么参数。

Any hints?有什么提示吗?

Here is a version using proposed standard filesystem library:这是一个使用建议的标准文件系统库的版本:

#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";
} 

Unless your goal is to learn how to write a recursive function, you might prefer this simple loop based on Boost.Filesystem :除非您的目标是学习如何编写递归函数,否则您可能更喜欢这个基于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
  }
}

Or even the single function call:甚至是单个函数调用:

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

My approach in C++11:我在 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);
    }
}

Usage:用法:

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

Isolate that code in a procedure that takes the base directory path as a parameter, so you can actually perform the recursive call.将该代码隔离在一个将基本目录路径作为参数的过程中,这样您就可以实际执行递归调用。 It should be something like应该是这样的

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

Then, to check if the pdir you obtained is a directory, you have two routes:然后,检查你得到的pdir是否是一个目录,你有两条路线:

  • you can check if pdir->d_type==DT_DIR ;你可以检查pdir->d_type==DT_DIR this gives you this information immediately, but it's not portable (POSIX does not mandate the existence of the d_type member);这会立即为您提供此信息,但它不可移植(POSIX 不d_type成员的存在); also, it's not supported for all the filesystems, so you may get DT_UNKNOWN .此外,并非所有文件系统都支持它,因此您可能会得到DT_UNKNOWN If you want to follow symlinks, you have to perform extra checks also if you get DT_LNK .如果你想跟随符号链接,如果你得到DT_LNK ,你还必须执行额外的检查。 In these cases, you must fall back to lstat (see the point below);在这些情况下,您必须回退到lstat (请参阅下面的要点);
  • you can instead portably use lstat to get information about each file, checking in particular the st_mode field of struct stat .您可以改为方便地使用lstat来获取有关每个文件的信息,特别是检查struct statst_mode字段。

Using C++17 recursive_directory_iterator it becomes as concise as:使用 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';
        }
    }
}

With example output:使用示例输出:

"/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"

It uses standard c++ functionality.它使用标准的 c++ 功能。 No need to include any third party library in code.无需在代码中包含任何第三方库。

Only send directory path as parameter.仅将目录路径作为参数发送。 It will revert you every files path present in that folder and its sub folder.它将还原该文件夹及其子文件夹中存在的每个文件路径。

Further that, if you need to sort any specific type file (ie .txt or.jpg), pass extension, it will print all the files path which having respective extension.此外,如果您需要对任何特定类型的文件(即 .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;
}

Path should look like /your_path/ .路径应该类似于/your_path/ For search inside hidden folders you should add third parameter true .要在隐藏文件夹中搜索,您应该添加第三个参数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);
}

You could check if there is no "."您可以检查是否没有“。” in the string.在字符串中。

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

Here how I use it这是我如何使用它

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;
    }

Great stuff, Here is my Windows friendly solution using std only since i had few bumps with the above solutions on Windows specifically: works in DLLs as well:很棒的东西,这是我仅使用 std 的 Windows 友好解决方案,因为我在 Windows 上对上述解决方案没有什么特别的意见:也适用于 DLL:

 #include <windows.h> // messagebox

 #define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING

 #include <filesystem> // C++17 standard header file name
 #include <experimental/filesystem> // Header file for pre-standard implementation

 using namespace std::experimental::filesystem::v1;

 for (recursive_directory_iterator next(path(dir.c_str())), end; next != end; ++next)
 {
    auto path = next->path();
    if (path.has_extension())
    {
        MessageBox(0, path.wstring().c_str(), L"Filepath", 0);
    }
 }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用 std::filesystem 实现递归目录和文件列表? - How to implement recursive directories and files listing using std::filesystem? C ++中的递归列表文件不会进入所有子目录 - Recursive listing files in C++ doesn't enter all subdirectories 在所有子目录中查找所有头文件 - Find all header files in all sub-directories 如何编译多个子目录中的所有cpp文件? - How to compile all cpp files in multiple sub directories? 递归函数搜寻器目录未检测到所有文件夹 - recursive function crawler directories dont detect all folders 使用纯c ++(跨平台)获取特定路径中的所有目录/文件和子目录 - Get all directories/files and sub-directories in a specific path using pure c++ (cross-platform) 删除目录及其中的所有子目录 - removing directories and all sub-directories in it 在android.mk目录和子目录中创建所有.cpp文件的FILE_LIST - Creating a FILE_LIST of all .cpp files in a directory and sub directories in android.mk 一种使用boost和c ++列出目录和子目录中所有文件的方法 - A method to list all files in directory and sub-directories using boost and c++ 如何获取目录和子目录中所有文件的列表(完整文件路径) - how to get list of all files in a directory and sub directories(full file path)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM