我正在修复一个大型的开源跨平台应用程序,以便它可以处理Windows上包含非ANSI字符的文件路径。
我当前的解决方案涉及:
在Windows上将.UTF-8
类别的C语言环境设置为LC_CTYPE
(所有其他类别均根据应用程序的需要设置为C
语言环境:]
// Required by the application.
std::setlocale(LC_ALL, "C");
// On Windows, we want std::fopen() and other functions dealing with strings
// and file paths to accept narrow-character strings encoded in UTF-8.
#ifdef _WIN32
{
#ifndef NDEBUG
char* new_ctype_locale =
#endif
std::setlocale(LC_CTYPE, ".UTF-8");
assert(new_ctype_locale != nullptr);
}
#endif
配置boost::filesystem::path
以使用en_US.UTF-8
语言环境,以便它也可以处理包含非ANSI字符的路径:
boost::filesystem::path::imbue(std::locale("en_US.UTF-8"));
最后遗漏的一点是使用C ++流修复文件I / O,例如
std::ifstream istream(filename);
最简单的解决方案可能是在应用程序的开头设置全局C ++语言环境:
std::locale::global(std::locale("en_US.UTF-8"));
然而,这弄乱了数字的格式,例如1234.56的格式设置为1,234.56。
是否有一个语言环境just将编码指定为UTF-8,而不会弄乱数字格式(或其他东西)?
基本上,我正在寻找C.UTF-8
语言环境,但是Windows似乎不存在。
更新:我想一种解决方案是重设语言环境的某些(大部分?全部?)方面,但是我很难找到有关如何执行此操作的信息。
没关系的语言环境。
在Windows上,您应该使用Microsoft's extension,该构造函数将const std::wchar_t*
(预期指向UTF-16的指针)添加到std::ifstream
。
希望您的所有字符串都是UTF-8,或其他一些一致且合理的编码。
因此,只需抓住一个UTF-8→UTF-16转换器(它们是轻量级的,并将文件名作为UTF-16(在std::ifstream
中)传递给std::wchar_t*
。
((请确保将其压缩为#ifdef
,以便在任何其他平台上都不会尝试。)
出于相同的原因,您也应以相同的方式使用_wfopen
代替_wfopen
。
就是这样。
Windows API不尊重CRT语言环境,std::fopen
等的CRT实现直接调用窄字符API,因此更改语言环境不会影响编码。
但是,Windows 10 May 2019更新(版本1903)fopen
。可以通过将适当的清单嵌入可执行文件中来启用它。不幸的是,这是一个非常新的功能,因此如果您需要定位较旧的系统,则可能无法选择。
您的其他选择包括手动转换为introduced a support for UTF-8 in its narrow-char APIs或使用为您完成此操作的层(例如Boost.Filesystem,或更佳的是wchar_t
)。