什么是std :: wifstream :: getline对我的wchar_t数组做什么?在getline返回后,它被视为一个字节数组

cha*_*era 1 stl unicode-string visual-c++

我想从文件中读取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();
Run Code Online (Sandbox Code Playgroud)

为了便于说明,假设input.txt包含两条UTF-16 LE线,其长度小于200个wchar_t个字符.

在第一次调用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")缓冲区包含(hex)"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 ...为什么?

我将不胜感激任何理解这些问题的见解和解释.

Igo*_*nik 8

wifstream从文件中读取字节,并使用codecvt安装在流的语言环境中的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>));
Run Code Online (Sandbox Code Playgroud)