如何逐步遍历目录树?
Posted
技术标签:
【中文标题】如何逐步遍历目录树?【英文标题】:How to walk through directory tree step by step? 【发布时间】:2015-04-10 07:57:12 【问题描述】:我发现了许多关于遍历目录树的示例,但我需要一些不同的东西。我需要一个带有某种方法的类,每个调用从目录中返回一个文件并逐渐遍历目录树。请问我该怎么做?我正在使用函数 FindFirstFile、FindNextFile 和 FindClose,我是 C++ 的新手。我有这样的东西......
例如我有这个简单的目录树
Parent(folder)\
file1.txt
file2.txt
Child(folder)\
file3.txt
file4.txt
我需要一个带有方法的类,例如 getNextFile(),第一次调用返回 file1.txt;第二次调用返回file2.txt,第三次调用返回Child(文件夹),第四次调用返回file3.txt,以此类推……
在重复标志上编辑:我基本上需要在没有 do/while、while 或 for 的情况下遍历树...我需要某种迭代器,它可以存储以供以后使用,并且可以在我中断时从上一个文件继续浏览,但最好只使用 winapi 调用
WIN32_FIND_DATA fdFile;
HANDLE hFind = NULL;
if((hFind = FindFirstFile(sPath, &fdFile)) == INVALID_HANDLE_VALUE)
return false;
do
//do some job with fdFile
while(FindNextFile(hFind, &fdFile));
【问题讨论】:
请说出您的问题到底是什么。你是想下到子目录不知道怎么做,还是想建一个类来封装上面的代码? 我编辑了一个帖子,希望它会更清晰。 你用的是哪个版本的VS? 2010溢价,重要吗?我以为VS的版本对c++源码没有太大影响。 How do you iterate through every file/directory recursively in standard C++? 的可能重复项 【参考方案1】:这是在 Windows 平台上执行此操作的原生 C++ 方式(使用 MFC 框架):
void ListFiles(const CString& sPath)
CFileFind finder;
CString sWildcard(sPath);
sWildcard += _T("\\*.*");
BOOL bWorking = finder.FindFile(sWildcard);
while (bWorking)
bWorking = finder.FindNextFile();
if (finder.IsDots())
continue;
if (finder.IsDirectory())
CString sFilePath = finder.GetFilePath();
// TODO: do stuff here
ListFiles(sFilePath);
finder.Close();
您可以更改通配符字符串以针对特定文件,例如 *.txt 等。您也可以将其作为参数传递给此函数以使其更通用。
【讨论】:
没有 OP 要求的迭代器。我仍然会给你一个赞成票,因为这是这样做的正确方法。我不太确定您是否正确处理了 Windows 文件系统模型中一些比较晦涩的功能... 是的,它使用 MFC。谢谢,这可能是一个解决方案,但在理想情况下,我需要一个迭代器,而不是 while 循环。但仍然感谢您并点赞。【参考方案2】:使用正确的工具。 Boost 随处可用,并且有您想要的方法。
来自http://rosettacode.org/wiki/Walk_a_directory/Recursively#C.2B.2B:
#include "boost/filesystem.hpp"
#include "boost/regex.hpp"
#include <iostream>
using namespace boost::filesystem;
int main()
path current_dir("."); //
boost::regex pattern("a.*"); // list all files starting with a
for (recursive_directory_iterator iter(current_dir), end;
iter != end;
++iter)
std::string name = iter->path().filename().string();
if (regex_match(name, pattern))
std::cout << iter->path() << "\n";
如果您不在乎您的文件是否与某个模式匹配,请删除整个正则表达式业务。
编辑:
您能否解释一下为什么直接使用 API 调用会不好?
-
丑陋且难以阅读,更难正确,
它根本不便携,最重要的是,
在使用原始 win api 时,您可能需要处理一百万个极端情况。 Boost 的编写者已经这样做了几百次,并且经过了认真的代码审查,因此请采取保存路线,不要重新发明***。
本质上,winapi 大约有 20 年的历史;世界其他地方的可用性得到了很多的改进。除非您有充分的理由,否则我会尝试通过使用常见的库(例如 Boost)来尽可能多地抽象它。
我认为这并不能解决我的问题,我编辑了原始帖子以使其更清晰。
基本上不需要do/while,while或for...我需要某种迭代器,可以存储以备后用
这正是我的回答所做的:在 for 循环中给你一个迭代器。我不明白什么不符合您的编辑规范。
另外,最好只使用 WinAPI,因为它必须在不同的带有 windows 的计算机上工作,安装 boost 可能是个问题。
您不必在这些计算机上安装 boost。 Boost::filesystem 可以轻松地静态链接;此外,老式的 Windows 方法只是提供 boost_filesystem*.dll
和 boost_system*.dll
以及您的二进制文件。但是,如果您的目标是包含所有必需功能的单个可执行文件,那么无论如何您都会选择静态链接,所以这绝对没有问题。
【讨论】:
您能否解释一下为什么直接使用 API 调用会不好? 可移植性可能是也可能不是问题(你说得对,这是提升的重点)。但是,是的,性能也可能是一个问题,或者在大中型组织的数百或数千台 PC 上安装 boost 的必要性。在某些用例中,boost 是正确的工具,而在其他用例中,API 是正确的。 我认为这并不能解决我的问题,我编辑了原始帖子以使其更清晰。此外,最好只使用 WinAPI,因为它必须在不同的带有 windows 的计算机上工作,并且安装 boost 可能是一个问题。 @SergeBallesta:我真的怀疑在处理目录树遍历时,boost 的迭代器方案的开销是否相关——在获得单个文件路径之前发生了很多事情,尤其是因为OP 表示使用迭代器是可取的。 只是一个提示:我喜欢对 cmets 做出反应;我不喜欢投反对票:)以上是关于如何逐步遍历目录树?的主要内容,如果未能解决你的问题,请参考以下文章