在 Windows 上,我尝试迭代并收集目录中的所有文件,另外我想处理长路径,这就是为什么我添加了长路径前缀 (L"\?\")。但它会因 c++17 的 std::filesystem 而崩溃。我也尝试过使用 boost::filesystem 进行相同的操作,它也崩溃了,但是如果我不添加前缀,它就可以工作。我希望这段代码主要适用于任何版本的 windows-10/11。我如何处理遇到长路的可能性。
void IterateDir(const std::string& newDir)
{
namespace fs = std::filesystem;
fs::path rootPath;
std::wstring wpath(newDir.begin(), newDir.end());
wpath = std::wstring(L"\\\\?\\") + wpath;
rootPath.assign(wpath);
for (auto iter = fs::recursive_directory_iterator(rootPath);
iter != fs::recursive_directory_iterator();
++iter) {
try {
auto file = *iter;
std::string filename = file.path().filename().string();
std::cout << "\nfile: " << filename;
}
catch (const std::exception& e) {
std::cout << "Exception while iterating directory." + std::string(e.what());
}
catch (...) {
std::cout << "Unknown exception while iterating directory.";
}
}
}
提前致谢:)
我发现,在迭代 wstring 中具有长路径前缀的目录时,C++ 17 文件系统存在崩溃的已知问题。该问题是由 filesystem::recursive_directory_iterator 处理文件的方式引起的。当迭代器到达带有 Unicode 字符的文件时,它会崩溃。
对象管理器路径不适用于
std::filesystem
或 boost::filesystem
(您需要特定于平台的 API,如 NtOpenDirectoryObject
、NtQueryDirectoryObject
)。
也就是说,两个库都不应该崩溃。除非出现错误(这种情况不太可能发生,如果它们咬了你,你可能可以升级库来修复它),你可能只是遇到权限错误,这将导致引发运行时异常。
因此,这是一个简化代码的版本,同时添加了最少的预防措施来处理遍历过程中的权限问题:
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
void IterateDir(fs::path dir, char const* nsPrefix = R"(\\?\)") {
auto flags = fs::directory_options::skip_permission_denied;
for (auto&& entry : fs::recursive_directory_iterator(nsPrefix / dir, flags)) {
try {
std::cout << "file: " << entry.path().filename() << "\n";
} catch (std::exception const& e) {
std::cout << "Exception while iterating directory." + std::string(e.what()) << "\n";
} catch (...) {
std::cout << "Unknown exception while iterating directory.\n";
}
}
}
int main() {
IterateDir(".", "");
IterateDir(".");
}
您可以看到第一次迭代的效果:
file: "main.cpp"
file: "a.out"
第二个引发异常(未处理,导致程序终止):
terminate called after throwing an instance of 'std::filesystem::__cxx11::filesystem_error'
what(): filesystem error: recursive directory iterator cannot open directory: No such file or directory [\\?\/.]
在 Windows 上,您可能会得到不同的行为,但绝对不会发生崩溃。
Boost 版本在 Coliru 上直播
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
显示相同的输出,但例外情况是:
terminate called after throwing an instance of 'boost::filesystem::filesystem_error'
what(): boost::filesystem::directory_iterator::construct: No such file or directory [system:2]: "\\?\/."