【问题标题】:Find all files in all directories in c++在c++中查找所有目录中的所有文件
【发布时间】:2023-10-14 05:44:01
【问题描述】:

我正在尝试查找所有目录中的所有文件,但我不知道如何处理子目录。在这段代码中,代码看起来穿过所有子目录,但我不知道如何跳回去。有谁知道怎么做?

__declspec(dllexport) void GetFiles(char* filedir, char* path)
{
    string s[1000];
    string path2 = path;
    UINT index = 0;

    WIN32_FIND_DATA ffd;
    TCHAR szDir[MAX_PATH];
    HANDLE hFind = INVALID_HANDLE_VALUE;
    DWORD dwError=0;

    StringCchCopy(szDir, MAX_PATH, filedir);

    if (INVALID_HANDLE_VALUE == hFind) 
        return;

    do
    {

        DWORD attributes = ffd.dwFileAttributes;

        if (attributes & FILE_ATTRIBUTE_HIDDEN)
            continue;
        else if (attributes & FILE_ATTRIBUTE_DIRECTORY)
        {
            TCHAR dir2[MAX_PATH];
            path2 = path;
            path2 += ffd.cFileName;
            path2 += "\\*";
            StringCchCopy(dir2, MAX_PATH, path2.c_str());
            SetCurrentDirectory(dir2);
        }
        else
        {
            s[index] = path;
            s[index] += ffd.cFileName;
            index++;
        }
    }
    while (FindNextFile(hFind, &ffd) >= 0); // needs to jump back if zero

    FindClose(hFind);
}

编辑:函数具有相同的名称,使编译器感到困惑

【问题讨论】:

  • 仅更改当前目录不会更改FindFirstFileFindNextFile 搜索的位置。您可以使用相同的函数递归搜索子目录,或者您可以进行广度优先搜索,但保留需要搜索的目录队列(其中,当您遇到目录时,您只需将其推入队列) .
  • 你可能想提防“。”和“..”,因为它们倾向于(实际上)导致无限枚举。

标签: c++ file search find


【解决方案1】:

我认为最简单的方法是使用递归函数。

这在“c”伪代码中大致看起来像这样

void GetFiles( char*** file_path_table, char* dir )
{
   char **file_paths;
   file_paths = getAllFiles( dir );
   foreach( path in file_paths )
   {
       if ( is_directory( path ) )
       {
           GetFiles( file_path_table, path );
       }
       else
       {
           add_file_to_table( file_path_table, path );
       }
   }
}

【讨论】:

  • is_directory() 是否会检测到指向同一树中更高位置的目录的符号链接(有效地使您的树成为图)?
  • 这将是特定于实现的,取决于您想要做什么。如果你想跟随符号链接,你应该进行检查以避免触发无限循环。
【解决方案2】:

为什么不使用提升recursive_directory_iterator

注意:未经测试(但应该看起来像这样)。

namespace bfs = boost::filesystem;

std::vector<std::string>    filenames;

std::copy(bfs::recursive_directory_iterator("<path>"),
          bfs::recursive_directory_iterator(),
          std::back_inserter(filenames)
         );

【讨论】:

    【解决方案3】:

    不要通过SetCurrentDirectory() 更改目录,而是在GetFiles() 上使用递归调用。这将要求调用者传入对要存储的文件列表的数组(或std::vector&lt;std::string&gt;)的引用,而不是使用本地数组s

    【讨论】:

      【解决方案4】:

      我会看看 boost 的目录迭代器。

      http://www.boost.org/doc/libs/1_51_0/libs/filesystem/doc/index.htm

      有一些示例涵盖了您正在尝试做的事情,并且几乎适用于您能想到的任何操作系统。

      看一下示例 3。它显示了如何遍历目录的所有内容。如果你找到了一个你以前没有见过的新目录,你只需在上面做同样的事情。有测试告诉你文件是否是常规的,目录等,所以试试看。

      【讨论】:

        【解决方案5】:

        通过旧帖子进行一些搜索,我想我已经提到多次进行广度优先搜索,但从未真正发布代码来展示如何做到这一点。我想我也可以这样做。

        #include <windows.h>
        #include <queue>
        #include <string>
        #include <iostream>
        
        // I think MS's names for some things are obnoxious.
        const HANDLE HNULL = INVALID_HANDLE_VALUE;
        const int A_DIR = FILE_ATTRIBUTE_DIRECTORY;
        
        // We'll process a file by printing its path/name
        void process(std::string const &path, WIN32_FIND_DATA const &file) { 
            std::cout << path << file.cFileName << "\n";
        }
        
        void find_file(std::string const &folder_name, std::string const &fmask) {
            HANDLE finder;          // for FindFirstFile
            WIN32_FIND_DATA file;   // data about current file.
            std::priority_queue<std::string, std::vector<std::string>,
                               std::greater<std::string> > dirs;
            dirs.push(folder_name); // start with passed directory 
        
            do {
                std::string path = dirs.top();// retrieve directory to search
                dirs.pop();
        
                if (path[path.size()-1] != '\\')  // normalize the name.
                    path += "\\";
        
                std::string mask = path + fmask;    // create mask for searching
        
                // traverse a directory. Search for sub-dirs separately, because we 
                // don't want a mask to apply to directory names. "*.cpp" should find
                // "a\b.cpp", even though "a" doesn't match "*.cpp".
                //
                // First search for files:
                if (HNULL==(finder=FindFirstFile(mask.c_str(), &file))) 
                    continue;
        
                do { 
                    if (!(file.dwFileAttributes & A_DIR))
                        process(path, file);
                } while (FindNextFile(finder, &file));
                FindClose(finder);
        
                // Then search for subdirectories:
                if (HNULL==(finder=FindFirstFile((path + "*").c_str(), &file)))
                    continue;
                do { 
                    if ((file.dwFileAttributes & A_DIR) && (file.cFileName[0] != '.'))
                        dirs.push(path + file.cFileName);
                } while (FindNextFile(finder, &file));
                FindClose(finder);
            } while (!dirs.empty());
        }
        
        int main(int argc, char **argv) { 
            if (argc > 2)
                find_file(argv[1], argv[2]);
            else
                find_file("C:\\", "*");
            return 0;
        }
        

        【讨论】:

          最近更新 更多