使用 std::filesystem::path 处理 std::string/std::wstring 的跨平台方式
Cross-platform way to handle std::string/std::wstring with std::filesystem::path
我有一段 C++ 代码示例在 Linux:
上抛出异常
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
抛出的异常是:filesystem error: Cannot convert character sequence: Invalid in or incomplete multibyte or wide character
我推测这个问题与 ç
字符的使用有关。
- 为什么这个宽字符串 (wchar_t) 是 "invalid or incomplete multibyte or wide character"?
- 展望未来,我如何使相关代码跨平台到 Windows and/or Linux 上的 运行。
- 我需要使用辅助函数吗?
- 我需要从程序员的 PoV 中强制执行哪些规则?
- 我在这里看到 response 说 "Don't use wide strings on Linux",我对 Windows 使用相同的规则吗?
Linux环境(别忘了我想运行跨平台):
- Ubuntu 18.04.3
- 海湾合作委员会 9.2.1
- C++17
不幸的是,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
//windows I/O setup
_setmode(_fileno(stdin), _O_WTEXT);
_setmode(_fileno(stdout), _O_WTEXT);
#endif
fs::path path = fs::u8path(u8"ελληνικά.txt");
#ifdef _WINDOWS_PLATFORM
std::wcout << "UTF16: " << path << std::endl;
#else
std::cout << "UTF8: " << path << std::endl;
#endif
或者使用您自己的宏为 Windows (L"string"
) 设置 UTF16,为基于 Unix 的系统设置 UTF8(u8"string"
或只是 "string"
)。确保为 Windows.
定义了 UNICODE
#ifdef _WINDOWS_PLATFORM
#define _TEXT(quote) L##quote
#define _tcout std::wcout
#else
#define _TEXT(quote) u8##quote
#define _tcout std::cout
#endif
fs::path path(_TEXT("ελληνικά.txt"));
_tcout << path << std::endl;
另见
https://en.cppreference.com/w/cpp/filesystem/path/native
注意,Visual Studio 有一个用于 std::fstream
的特殊构造函数,它允许使用 UTF16 文件名,并且它与 UTF8 read/write 兼容。例如,以下代码将在 Visual Studio: 中工作
fs::path utf16 = fs::u8path(u8"UTF8 filename ελληνικά.txt");
std::ofstream fout(utf16);
fout << u8"UTF8 content ελληνικά";
我不确定 Windows 上的最新 gcc 版本 运行 是否支持它。
看起来像 a GCC bug。
根据 std::filesystem::path::path,您应该能够使用宽字符串调用 std::filesystem::path 构造函数,并且独立于底层平台(这就是 std::filesystem 的重点)。
Clang 显示正确的行为。
我有一段 C++ 代码示例在 Linux:
上抛出异常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
抛出的异常是:filesystem error: Cannot convert character sequence: Invalid in or incomplete multibyte or wide character
我推测这个问题与 ç
字符的使用有关。
- 为什么这个宽字符串 (wchar_t) 是 "invalid or incomplete multibyte or wide character"?
- 展望未来,我如何使相关代码跨平台到 Windows and/or Linux 上的 运行。
- 我需要使用辅助函数吗?
- 我需要从程序员的 PoV 中强制执行哪些规则?
- 我在这里看到 response 说 "Don't use wide strings on Linux",我对 Windows 使用相同的规则吗?
Linux环境(别忘了我想运行跨平台):
- Ubuntu 18.04.3
- 海湾合作委员会 9.2.1
- C++17
不幸的是,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
//windows I/O setup
_setmode(_fileno(stdin), _O_WTEXT);
_setmode(_fileno(stdout), _O_WTEXT);
#endif
fs::path path = fs::u8path(u8"ελληνικά.txt");
#ifdef _WINDOWS_PLATFORM
std::wcout << "UTF16: " << path << std::endl;
#else
std::cout << "UTF8: " << path << std::endl;
#endif
或者使用您自己的宏为 Windows (L"string"
) 设置 UTF16,为基于 Unix 的系统设置 UTF8(u8"string"
或只是 "string"
)。确保为 Windows.
UNICODE
#ifdef _WINDOWS_PLATFORM
#define _TEXT(quote) L##quote
#define _tcout std::wcout
#else
#define _TEXT(quote) u8##quote
#define _tcout std::cout
#endif
fs::path path(_TEXT("ελληνικά.txt"));
_tcout << path << std::endl;
另见
https://en.cppreference.com/w/cpp/filesystem/path/native
注意,Visual Studio 有一个用于
std::fstream
的特殊构造函数,它允许使用 UTF16 文件名,并且它与 UTF8 read/write 兼容。例如,以下代码将在 Visual Studio: 中工作
fs::path utf16 = fs::u8path(u8"UTF8 filename ελληνικά.txt");
std::ofstream fout(utf16);
fout << u8"UTF8 content ελληνικά";
我不确定 Windows 上的最新 gcc 版本 运行 是否支持它。
看起来像 a GCC bug。
根据 std::filesystem::path::path,您应该能够使用宽字符串调用 std::filesystem::path 构造函数,并且独立于底层平台(这就是 std::filesystem 的重点)。
Clang 显示正确的行为。