我正在尝试使用 wifstream 打开文件:
#include <sstream>
#include <fstream>
wstring readFile(const char* filename)
{
wifstream wif(filename);
wstringstream wss;
wss << wif.rdbuf();
return wss.str();
}
它正在读取包含英文和俄文符号的文件并将文本放入wstring中。
然后,我尝试将所有这些打印到控制台中,所有俄语符号都被替换为另一个符号。英文符号正确。
我发现,替换符号的所有字符代码(如\u...)都是正确的。而且它们不在 ASCII 表中,例如 å - U+00E5 (en.wikipedia.org/wiki/List_of_Unicode_characters)
我认为将文件解码为 utf-8 时存在问题。
无需任何额外设置,
wifstream
将使用 C
语言环境,这可能不是您想要的。
有多种可能的解决方案:
要使用默认区域设置读取文件,请将
std::wifstream
与 std::locale("")
结合使用。这就是大多数 Linux 程序的工作方式。
示例:
#include <fstream>
#include <iostream>
#include <ranges>
int main()
{
std::wifstream stream("sample.txt");
if (!stream)
{
std::cerr << "Failed to open file\n";
return 1;
}
stream.imbue(std::locale(""));
for (auto c : std::views::istream<wchar_t>(stream))
{
std::cout << std::hex << static_cast<int>(c) << std::endl;
}
if (stream.bad())
{
std::cerr << "Failed to extract character\n";
}
}
大多数 Linux 发行版默认使用 UTF-8。 Windows 也可以配置为使用 UTF-8,尽管我相信这不是默认设置。
虽然没有真正完全可移植的方法来执行此操作,但以下内容似乎在 Windows 和 Linux 上都适用(只要
en_US.utf-8
语言环境可用):
stream.imbue(std::locale("en_US.utf-8"));
codecvt_utf8_utf16
警告:请勿在生产中使用。
<codecvt>
中的内容存在与错误处理相关的问题,并将从标准中删除。我也不相信他们能够正确处理格式错误(或潜在恶意)的输入。
stream.imbue(std::locale(std::locale::classic(), new std::codecvt_utf8_utf16<wchar_t>));
对于不能简单依赖默认语言环境的生产代码来说,这实际上是最佳选择。
那么您应该选择哪种方法呢?这取决于: