如何在c++17中使用std::filesystem处理长路径

问题描述 投票:0回答:1

在 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 字符的文件时,它会崩溃。

boost windows-10 c++17 boost-filesystem std-filesystem
1个回答
0
投票

对象管理器路径不适用于

std::filesystem
boost::filesystem
(您需要特定于平台的 API,如
NtOpenDirectoryObject
NtQueryDirectoryObject
)。

也就是说,两个库都不应该崩溃。除非出现错误(这种情况不太可能发生,如果它们咬了你,你可能可以升级库来修复它),你可能只是遇到权限错误,这将导致引发运行时异常。

因此,这是一个简化代码的版本,同时添加了最少的预防措施来处理遍历过程中的权限问题:

住在Coliru

#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]: "\\?\/."
© www.soinside.com 2019 - 2024. All rights reserved.