Zer*_*ect 6 character-encoding std-filesystem
我有一段在 Linux 上引发异常的 C++ 代码示例:
namespace fs = std::filesystem;
const fs::path pathDir(L"/var/media");
const fs::path pathMedia = pathDir / L"COMPACTO - Diogo Poças.mxf" // <-- Exception thrown here
Run Code Online (Sandbox Code Playgroud)
抛出的异常是: filesystem error: Cannot convert character sequence: Invalid in or incomplete multibyte or wide character
我推测这个问题与ç字符的使用有关。
Linux 环境(不要忘记我想跨平台运行的事实):
不幸的std::filesystem是,编写时并没有考虑到操作系统兼容性,至少没有像宣传的那样。
对于基于 Unix 的系统,我们需要 UTF8(u8"string"或仅"string"取决于编译器)
对于 Windows,我们需要 UTF16 ( L"string")
在 C++17 中你可以使用filesystem::u8path(由于某种原因在 C++20 中已弃用)。在 Windows 中,这会将 UTF8 转换为 UTF16。现在您可以将 UTF16 传递给 API。
#ifdef _WINDOWS_PLATFORM\n //windows I/O setup\n _setmode(_fileno(stdin), _O_WTEXT);\n _setmode(_fileno(stdout), _O_WTEXT);\n#endif\n\nfs::path path = fs::u8path(u8"\xce\xb5\xce\xbb\xce\xbb\xce\xb7\xce\xbd\xce\xb9\xce\xba\xce\xac.txt");\n\n#ifdef _WINDOWS_PLATFORM\n std::wcout << "UTF16: " << path << std::endl;\n#else\n std::cout << "UTF8: " << path << std::endl;\n#endif\nRun Code Online (Sandbox Code Playgroud)\n\n或者使用您自己的宏为 Windows 设置 UTF16 ( L"string"),为基于 Unix 的系统设置 UTF8 (u8"string"或只是"string")。确保UNICODE是为 Windows 定义的。
#ifdef _WINDOWS_PLATFORM\n#define _TEXT(quote) L##quote\n#define _tcout std::wcout\n#else\n#define _TEXT(quote) u8##quote\n#define _tcout std::cout\n#endif\n\nfs::path path(_TEXT("\xce\xb5\xce\xbb\xce\xbb\xce\xb7\xce\xbd\xce\xb9\xce\xba\xce\xac.txt"));\n_tcout << path << std::endl;\nRun Code Online (Sandbox Code Playgroud)\n\n另请参阅
\n https://en.cppreference.com/w/cpp/filesystem/path/native
std::fstream,允许使用 UTF16 文件名,并且它兼容 UTF8 读/写。例如,以下代码将在 Visual Studio 中运行:\n\nfs::path utf16 = fs::u8path(u8"UTF8 filename \xce\xb5\xce\xbb\xce\xbb\xce\xb7\xce\xbd\xce\xb9\xce\xba\xce\xac.txt");\nstd::ofstream fout(utf16);\nfout << u8"UTF8 content \xce\xb5\xce\xbb\xce\xbb\xce\xb7\xce\xbd\xce\xb9\xce\xba\xce\xac";\nRun Code Online (Sandbox Code Playgroud)\n\n我不确定 Windows 上运行的最新 gcc 版本是否支持这一点。
\n看起来像一个海湾合作委员会错误。
根据std::filesystem::path::path您应该能够使用宽字符串调用 std::filesystem::path 构造函数,并且独立于底层平台(这就是 std::filesystem 的全部要点)。
Clang 显示了正确的行为。