问题描述
我想使用 std::filesystem::recursive_directory_iterator
类创建一个类方法,它遍历所有子目录并处理找到的 xml 文件。
我在互联网上找到的唯一方法是使用这样的 for 循环:
for (fs::directory_entry p : fs::recursive_directory_iterator("my_file"))
do_something(p);
问题是我需要在函数调用之间存储我的迭代器(或至少它指向的位置),因为我一次只能处理一个文件。我试着像这样实现它:
class C {
private:
std::filesystem::recursive_directory_iterator it;
std::filesystem::directory_entry p;
public:
C(std::filesystem::path);
std::string find_file();
};
C::C(std::filesystem::path path)
{
it = fs::recursive_directory_iterator(path);
p = fs::directory_entry(it.begin());
}
std::string C::find_file()
{
do { //using do while so my function won't load the same file twice
++p;
} while (!is_xml(p.path()) && p != it.end());
}
但似乎 std::filesystem::recursive_directory_iterator
没有 begin()
和 end()
方法,无法进行比较。
我不知道我的代码与工作范围循环有何不同,除了存储迭代器和有一个额外的条件。
解决方法
如果您查看 std::filesystem::recursive_directory_iterator Non-member functions,您可以看到:
// range-based for loop support
begin(std::filesystem::recursive_directory_iterator)
end(std::filesystem::recursive_directory_iterator)
然后 std::filesystem::begin(recursive_directory_iterator),std::filesystem::end(recursive_directory_iterator)
提供更多详细信息:
end(recursive_directory_iterator)
返回一个默认构造的 recursive_directory_iterator,用作结束迭代器。参数被忽略。
因此您将检查 it
是否不等于 std::end(it)
,然后查看是否还有更多元素。并且您必须增加 it
而不是 p
。
您还需要在执行it != std::end(it)
之前检查是否!is_xml(*it.path())
std::string C::find_file()
{
do { //using do while so my function won't load the same file twice
++it;
} while (it != std::end(it) && !is_xml(*it.path()));
}
,
recursive_directory_iterator
本身已经是一个迭代器(它的名字说得很对),所以你根本不需要使用 begin()
和 end()
。它实现了 operator==
、operator!=
、operator->
和 operator++
,在本例中您只需要这些。
此外,p
根本没有理由成为班级成员。应该是find_file()
的局部变量(其实这种情况下是可以完全消除的)。并且循环应该是 while
循环而不是 do..while
循环,以防在输入 find_file()
时迭代器已经处于“结束”。
试试这个:
class C {
private:
std::filesystem::recursive_directory_iterator it;
public:
C(std::filesystem::path);
std::string find_file();
};
C::C(std::filesystem::path path)
: it(path)
{
}
std::string C::find_file()
{
static std::filesystem::directory_iterator end;
while (it != end) {
auto p = it->path();
if (is_xml(p))
return p.string();
++it;
}
return "";
}