如何使用 std::filesystem::path 正确处理带有长路径前缀的 Windows 路径

rid*_*ous 8 c++ windows c++17 std-filesystem long-path

std::filesystem::path似乎不知道Windows 长路径 magic prefix。这是每个设计还是有可以使用的模式/标志/编译器开关/第三方库?

  • 对于像 之类的路径C:\temp\test.txtroot_nameisC:root_pathisC:\都是有效路径,但是
  • 因为\\?\C:\tmp\test.txt他们是\\?并且\\?\

我希望它们是C:C:\因为\\?\它不是路径,而只是一个用于解决旧版 Windows 260 字符路径限制的标签。

请参阅compilerexplorer 上的完整示例

Gug*_*ugi 6

正如上面的评论中提到的,Microsoft STL 的源代码显示当前行为是针对 UNC(统一命名约定)路径而设计的,并且没有“神奇的编译器开关”来更改此行为。此外,正如这篇 github 帖子std::filesystem所暗示的那样,UNC 路径似乎不应该与 一起使用。还有一个需要改变行为的未决问题。

由于 OP 可以使用第 3 方库:在 Windows 上为 UNC 路径boost::filesystem构建特殊代码,并给出更接近预期的结果。

使用以下代码进行尝试(改编自原始帖子):

#include <filesystem>
#include <iostream>
#include <string>
#include <vector>

#include <boost/filesystem.hpp>

int main()
{
  std::vector<std::string> tests = {
      R"(C:\temp\test.txt)",
      R"(\\?\C:\temp\test.txt)",
  };

  for (auto const & test : tests) {
    std::filesystem::path const p(test); // or boost::filesystem::path
    std::cout << std::endl << test << std::endl;
    std::cout << "root_name\t" << p.root_name().string() << std::endl;
    std::cout << "root_directory\t" << p.root_directory().string() << std::endl;
    std::cout << "root_path\t" << p.root_path().string() << std::endl;
    std::cout << "relative_path\t" << p.relative_path().string() << std::endl;
    std::cout << "parent_path\t" << p.parent_path().string() << std::endl;
    std::cout << "filename\t" << p.filename().string() << std::endl;
    std::cout << "stem\t" << p.stem().string() << std::endl;
    std::cout << "extension\t" << p.extension().string() << std::endl;
  }
}
Run Code Online (Sandbox Code Playgroud)

对于std::filesystemMSVC 我得到

C:\temp\test.txt
root_name       C:
root_directory  \
root_path       C:\
relative_path   temp\test.txt
parent_path     C:\temp
filename        test.txt
stem    test
extension       .txt

\\?\C:\temp\test.txt
root_name       \\?
root_directory  \
root_path       \\?\
relative_path   C:\temp\test.txt
parent_path     \\?\C:\temp
filename        test.txt
stem    test
extension       .txt
Run Code Online (Sandbox Code Playgroud)

因为boost::filesystem我得到:

C:\temp\test.txt
root_name       C:
root_directory  \
root_path       C:\
relative_path   temp\test.txt
parent_path     C:\temp
filename        test.txt
stem    test
extension       .txt

\\?\C:\temp\test.txt
root_name       \\?\C:
root_directory  \
root_path       \\?\C:\
relative_path   temp\test.txt
parent_path     \\?\C:\temp
filename        test.txt
stem    test
extension       .txt
Run Code Online (Sandbox Code Playgroud)