1

我想从文件中读取 Unicode 文本行(UTF-16 LE,换行符分隔)。我正在使用 Visual Studio 2012 并针对 32 位控制台应用程序。

我无法在 WinAPI 中找到 ReadLine 函数,所以我求助于 Google。很明显,我不是第一个寻求这种功能的人。最普遍推荐的解决方案是使用 std::wifstream。

我编写了类似于以下的代码:

wchar_t buffer[1024];
std::wifstream input(L"input.txt");

while (input.good())
{
    input::getline(buffer, 1024);
    // ... do stuff...
}

input.close();

为了便于解释,假设 input.txt 包含两个长度小于 200 wchar_t 字符的 UTF-16 LE 行。

在第一次调用 getline 之前,Visual Studio 正确识别该缓冲区是 wchar_t 数组。您可以将鼠标悬停在调试器中的变量上,并看到该数组由 16 位值组成。但是,在 getline 调用返回后,调试器现在将缓冲区显示为字节数组。

在第一次调用 getline 之后,缓冲区的内容是正确的(除了缓冲区被视为字节数组)。如果 input.txt 的第一行包含 UTF-16 字符串 L“123”,则该字符串在缓冲区中正确存储为(十六进制)“31 00 32 00 33 00”

我的第一个想法是reinterpret_cast<wchar_t *>(buffer)哪个确实产生了所需的结果(缓冲区现在被视为 wchar_t 数组)并且它包含我期望的值。

然而,在第二次调用 getline 之后,(input.txt 的第二行包含字符串 L“456”)缓冲区包含(十六进制)“00 34 00 35 00 36 00”。请注意,这是不正确的(应该是 [hex] 34 00 35 00 36 00)

字节顺序混乱的事实使我无法使用 reinterpret_cast 作为解决此问题的解决方案。更重要的是,为什么 std::wifstream::getline 甚至将我的 wchar_t 缓冲区转换为 char 缓冲区?我的印象是,如果有人想使用字符,他们会使用 ifstream,如果他们想使用 wchar_t,他们会使用 wifstream ...

我很难理解 stl 标头,但看起来 wifstream 似乎故意将我的 wchar_t 转换为 char ......为什么?

对于理解这些问题,我将不胜感激任何见解和解释。

4

1 回答 1

8

wifstreamcodecvt从文件中读取字节,并使用安装在流语言环境中的 facet将它们转换为宽字符。默认方面采用系统默认代码页并调用mbstowcs这些字节。

要将您的文件视为 UTF-16,您需要使用codecvt_utf16. 像这样

std::wifstream fin("text.txt", std::ios::binary);
// apply facet
fin.imbue(std::locale(fin.getloc(),
          new std::codecvt_utf16<wchar_t, 0x10ffff, std::little_endian>));
于 2013-10-31T04:27:52.687 回答