C++ 17 std :: filesystem :: path中的本机路径分隔符错误?

Gar*_*and 18 c++ c++17 std-filesystem

从升级当我遇到一个问题#include <experimental/filesystem>#include <filesystem>.似乎该std::filesystem::path::wstring方法没有返回与中相同的字符串experimental::filesystem.我编写了以下小测试程序,其中包含输出结果.

#include <iostream>
#include <filesystem>
#include <experimental/filesystem>

namespace fs = std::filesystem;
namespace ex = std::experimental::filesystem;
using namespace std;

int main()
{
    fs::path p1{ L"C:\\temp/foo" };    
    wcout << "std::filesystem Native: " << p1.wstring() << "  Generic: " << p1.generic_wstring() << endl;

    ex::path p2{ L"C:\\temp/foo" };
    wcout << "std::experimental::filesystem Native: " << p2.wstring() << "  Generic: " << p2.generic_wstring() << endl;
}

/* Output:
std::filesystem Native: C:\temp/foo  Generic: C:/temp/foo
std::experimental::filesystem Native: C:\temp\foo  Generic: C:/temp/foo
*/
Run Code Online (Sandbox Code Playgroud)

根据https://en.cppreference.com/w/cpp/filesystem/path/string:

返回值

本机路径名格式的内部路径名,转换为指定的字符串类型.

该程序在Windows 10上运行,并使用Visual Studio 2017版本15.8.0进行编译.我希望原生路径名是C:\temp\foo.

问题:这是一个错误std::filesystem::path吗?

Cás*_*nan 9

粗略地说,当它显示出由从所述编译器的文档发散的标准(显式或隐式地),或禁止行为的行为在编译器中的错误发生.

该标准对本机路径字符串的格式没有任何限制,除了底层操作系统应该接受该格式(下面引用).它怎么能施加这样的限制呢?该语言对主机操作系统如何处理路径没有发言权,并且要自信地完成它必须知道它可能被编译到的每个目标,这显然是不可行的.

[fs.class.path]

5    pathname是表示路径名称的字符串.路径名根据通用路径名格式的语法([fs.path.generic])或根据本发明的格式化的操作系统通过主机操作系统接受依赖的本地路径名格式.

(强调我的)

MSVC的文档意味着正斜杠完全可以作为分隔符:

两个系统的共同点是一旦超过根名称就强加给路径名的结构.对于路径名c:/abc/xyz/def.ext:

  • 根名称是c:.
  • 根目录是/.
  • 根路径是c:/.
  • 相对路径是abc/xyz/def.ext.
  • 父路径是c:/abc/xyz.
  • 文件名是def.ext.
  • 干是def.
  • 扩展名是.ext.

它确实提到了一个首选的分隔符,但这实际上只暗示std::make_preferred了默认路径输出的行为,而不是它的行为:

较小的差异是路径名中目录序列之间的首选分隔符.这两种操作系统都允许你编写正斜杠/,但在某些情况下,Windows更喜欢反斜杠\.

这是否是一个错误的问题,那么,很简单:既然标准对行为没有任何限制,以及编译器的文档意味着没有强制需要一个反斜杠,不能有任何错误.

左边是这是否是一个执行质量问题.毕竟,编译器和库实现者应该知道有关其目标的所有怪癖,并相应地实现功能.

你应该在Windows中使用什么斜杠('\'或者'/'),或者它是否真的重要,这是争论的焦点,所以没有权威性的答案.任何支持一方或另一方的答案都必须非常小心,不要过于舆论.而且,仅仅存在path::make_preferred表明本机路径不一定是优选路径.考虑零开销原则:使路径始终是首选路径会给那些在处理路径时不需要那种迂腐的人带来开销.

最后,std::experimental命名空间是它说包装盒上的:你不应该指望最终标准库行为相同,它的实验版本,甚至预计最终的标准化图书馆将存在于所有.在处理实验性的东西时,它就是这样.


Roi*_*ton 6

不,这不是一个错误!

string()et alc_str()/native()返回本路径名格式的内部路径名.

什么本地人的意思

MS声明,它使用ISO/IEC TS 18822:2015.最终草案定义了§4.11中的本机路径名格式,如下所示:

主机操作系统接受的操作系统相关路径名格式.

在Windows中,native()返回路径为std::wstring().

如何在Windows中强制使用反斜杠作为目录分隔符

该标准定义了术语 preferred-separator(另请参见§8.1(路径名格式语法)):

依赖于操作系统的目录分隔符.

可以将路径(就地)转换为首选分隔符path::make_preferred.在Windows中,它有noexcept运营商.

为什么你不要担心

关于路径MS文档说明了/vs 的用法\

Windows API中的文件I/O函数将"/"转换为"\"作为将名称转换为NT样式名称的一部分,除非使用"\?\"前缀,如以下部分所述.

关于C++文件导航文档中,斜杠(在较新的草稿中称为fallback-separator)甚至可以直接在根名称之后使用:

path pathToDisplay(L"C:/FileSystemTest/SubDir3/SubDirLevel2/File2.txt ");
Run Code Online (Sandbox Code Playgroud)

VS2017 15.8的示例-std:C++17:

#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;

void output(const std::string& type, fs::path& p)
{
    std::cout
        << type << ":\n"
        << "- native: " << p.string() << "\n"
        << "- generic: " << p.generic_string() << "\n"
        << "- preferred-separator" << p.make_preferred() << "\n";
}

int main()
{
    fs::path local_win_path("c:/dir/file.ext");
    fs::path unc_path("//your-remote/dir/file.ext");

    output("local absolute win path", local_win_path);
    output("unc path", unc_path);

    unc_path = "//your-remote/dir/file.ext"; // Overwrite make_preferred applied above.
    if (fs::is_regular_file(unc_path))
    {
        std::cout << "UNC path containing // was understood by Windows std filesystem";
    }
}
Run Code Online (Sandbox Code Playgroud)

可能的输出(当unc_path是现有遥控器上的现有文件时):

local absolute win path:
- native: c:/dir/file.ext
- generic: c:/dir/file.ext
- preferred-separator"c:\\dir\\file.ext"
unc path:
- native: //your-remote/dir/file.ext
- generic: //your-remote/dir/file.ext
- preferred-separator"\\\\your-remote\\dir\\file.ext"
UNC path containing // was understood by Windows std filesystem
Run Code Online (Sandbox Code Playgroud)

因此,只有在使用强制使用该分隔符进行文件系统交互的库时,才需要对preferred-separator进行显式路径转换.


Nic*_*las 5

其中任何一个都可以被视为平台上的"本机",因此这些选项中的任何一个都同样有效.无论平台如何,Filesystem API都不保证"本机"版本与您提供的字符串相同.如果通用"/"字符与它等效,那么"本机"字符串也不会保证只使用本机目录分隔符.

  • 许多但不是所有Windows API都接受"/".例如,[shell路径处理函数](https://msdn.microsoft.com/en-us/library/windows/desktop/bb773559(v = vs.85).aspx)只接受"\". (3认同)