std::filesystem::directory_iterator 之类的迭代器可以在循环外使用吗?
Can an iterator such as std::filesystem::directory_iterator be used outside of a loop?
我正在尝试了解如何在 C++ 中使用迭代器之类的东西,并且特别想更好地了解 std::filesystem::directory_iterator。
我理解这样简单的例子:
#include <iostream>
#include <filesystem>
#include <string>
void doSomething(std::string filename)
{
std::cout << filename;
};
int main()
{
auto iterator = std::filesystem::directory_iterator("c:/somefolder");
for (auto& i : iterator)
{
doSomething(std::filesystem::path(i.path()).filename().string());
}
}
但是很多遗留代码并不是在这样一个紧密的循环中编写的。是否可以以类似于 WinAPI FindNextFile() 的方式使用 directory_iterator?
与此类似的内容:
std::string getNextFilename(std::string path)
{
// Notice the actual filesystem access code is neatly packed away in a replaceable function suitable for a HAL.
static auto iterator = std::filesystem::directory_iterator(path);
return std::filesystem::path(iterator.path()).filename().string();
}
int main()
{
while (std::string fileName = getNextFilename("c:/somefolder"))
{
doSomething(fileName);
}
// or
std::string fileFirst = getNextFilename("c:/somefolder");
std::string fileSecond = getNextFilename("c:/somefolder");
std::string fileLast = getNextFilename("c:/somefolder");
}
请回答:
- 一般迭代器,能不能这样用,为什么?
- 具体如何一次执行一个 file/directory 的这种目录查找。
edit1:澄清标题。
手动递增迭代器很容易(因为这也是基于范围的 for
循环所做的)。但是您需要相应地调整其他代码,因为 std::string
没有 operator bool
。一种可能的解决方案(仅略微修改原始代码,仍然包含所有问题)可能如下所示(使用 std::optional<std::string>
启用返回“结束”条件):
#include <iostream>
#include <filesystem>
#include <string>
#include <optional>
void doSomething(std::string filename)
{
std::cout << filename;
};
std::optional<std::string> getNextFilename(std::string path)
{
static auto iterator = std::filesystem::directory_iterator(path);
if (iterator != std::filesystem::directory_iterator()) {
auto filename = std::filesystem::path(iterator->path()).filename().string();
++iterator; // advance iterator to next entry in directory
return filename; // uses implicit constructor of `std::optional`
} else {
return {}; // return empty optional if we reached end of directory
}
}
int main()
{
while (auto fileName = getNextFilename("c:/somefolder"))
{
doSomething(*fileName); // dereference optional to get value
}
// or
auto fileFirst = getNextFilename("c:/somefolder");
auto fileSecond = getNextFilename("c:/somefolder");
auto fileLast = getNextFilename("c:/somefolder");
}
假设您想要或多或少 drop-in 替代 FindFirstFile/FindNextFile,解决方案可能如下所示:
struct HANDLE{
std::filesystem::directory_iterator it;
};
bool FindNextFile(HANDLE &handle, std::string& output) {
if(handle.it == std::filesystem::directory_iterator{}) return false;
output=handle.it->path().string();
handle.it++;
return true;
}
HANDLE FindFirstFile(std::string input, std::string& output) {
HANDLE h;
h.it=std::filesystem::directory_iterator{input};
FindNextFile(h,output);
return h;
}
std::filesystem::path my_path("C:/");
for (std::filesystem::directory_iterator itt(my_path);
itt != std::filesystem::directory_iterator(); itt++)
{
const std::filesystem::directory_entry& entr = *itt;
std::string filename = entr.path().string();
}
这里好像没有begin()
和end()
。也没有 --
运算符。因此,例如从头到尾迭代它似乎是不可能的。也没有 size()
功能
我正在尝试了解如何在 C++ 中使用迭代器之类的东西,并且特别想更好地了解 std::filesystem::directory_iterator。
我理解这样简单的例子:
#include <iostream>
#include <filesystem>
#include <string>
void doSomething(std::string filename)
{
std::cout << filename;
};
int main()
{
auto iterator = std::filesystem::directory_iterator("c:/somefolder");
for (auto& i : iterator)
{
doSomething(std::filesystem::path(i.path()).filename().string());
}
}
但是很多遗留代码并不是在这样一个紧密的循环中编写的。是否可以以类似于 WinAPI FindNextFile() 的方式使用 directory_iterator?
与此类似的内容:
std::string getNextFilename(std::string path)
{
// Notice the actual filesystem access code is neatly packed away in a replaceable function suitable for a HAL.
static auto iterator = std::filesystem::directory_iterator(path);
return std::filesystem::path(iterator.path()).filename().string();
}
int main()
{
while (std::string fileName = getNextFilename("c:/somefolder"))
{
doSomething(fileName);
}
// or
std::string fileFirst = getNextFilename("c:/somefolder");
std::string fileSecond = getNextFilename("c:/somefolder");
std::string fileLast = getNextFilename("c:/somefolder");
}
请回答:
- 一般迭代器,能不能这样用,为什么?
- 具体如何一次执行一个 file/directory 的这种目录查找。
edit1:澄清标题。
手动递增迭代器很容易(因为这也是基于范围的 for
循环所做的)。但是您需要相应地调整其他代码,因为 std::string
没有 operator bool
。一种可能的解决方案(仅略微修改原始代码,仍然包含所有问题)可能如下所示(使用 std::optional<std::string>
启用返回“结束”条件):
#include <iostream>
#include <filesystem>
#include <string>
#include <optional>
void doSomething(std::string filename)
{
std::cout << filename;
};
std::optional<std::string> getNextFilename(std::string path)
{
static auto iterator = std::filesystem::directory_iterator(path);
if (iterator != std::filesystem::directory_iterator()) {
auto filename = std::filesystem::path(iterator->path()).filename().string();
++iterator; // advance iterator to next entry in directory
return filename; // uses implicit constructor of `std::optional`
} else {
return {}; // return empty optional if we reached end of directory
}
}
int main()
{
while (auto fileName = getNextFilename("c:/somefolder"))
{
doSomething(*fileName); // dereference optional to get value
}
// or
auto fileFirst = getNextFilename("c:/somefolder");
auto fileSecond = getNextFilename("c:/somefolder");
auto fileLast = getNextFilename("c:/somefolder");
}
假设您想要或多或少 drop-in 替代 FindFirstFile/FindNextFile,解决方案可能如下所示:
struct HANDLE{
std::filesystem::directory_iterator it;
};
bool FindNextFile(HANDLE &handle, std::string& output) {
if(handle.it == std::filesystem::directory_iterator{}) return false;
output=handle.it->path().string();
handle.it++;
return true;
}
HANDLE FindFirstFile(std::string input, std::string& output) {
HANDLE h;
h.it=std::filesystem::directory_iterator{input};
FindNextFile(h,output);
return h;
}
std::filesystem::path my_path("C:/");
for (std::filesystem::directory_iterator itt(my_path);
itt != std::filesystem::directory_iterator(); itt++)
{
const std::filesystem::directory_entry& entr = *itt;
std::string filename = entr.path().string();
}
这里好像没有begin()
和end()
。也没有 --
运算符。因此,例如从头到尾迭代它似乎是不可能的。也没有 size()
功能