Visual c++ std::wifstream::getline对我的wchar\t数组做了什么?它';在getline返回后,将其视为字节数组

Visual c++ std::wifstream::getline对我的wchar\t数组做了什么?它';在getline返回后,将其视为字节数组,visual-c++,stl,unicode-string,Visual C++,Stl,Unicode String,我想从文件中读取Unicode文本行(UTF-16 LE,换行符分隔)。我使用的是Visual Studio 2012,目标是32位控制台应用程序 我在WinAPI中找不到ReadLine函数,所以我求助于谷歌。显然,我不是第一个寻求这种功能的人。最常用的推荐解决方案包括使用std::wifstream 我编写了类似于以下内容的代码: wchar_t buffer[1024]; std::wifstream input(L"input.txt"); while (input.good()) {

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

我在WinAPI中找不到ReadLine函数,所以我求助于谷歌。显然,我不是第一个寻求这种功能的人。最常用的推荐解决方案包括使用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之前,VisualStudio正确地识别出缓冲区是一个wchar\u t数组。您可以将鼠标悬停在调试器中的变量上,看到数组由16位值组成。但是,在对getline的调用返回后,调试器现在显示缓冲区,就好像是字节数组一样

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

我的第一个想法是
重新解释cast(buffer)
,它确实产生了期望的结果(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\u t缓冲区转换成char缓冲区呢??我的印象是,如果想使用char,他们会使用ifstream;如果想使用wchar,他们会使用wifstream

我很难理解stl头,但wifstream似乎有意将我的wchar\u t转换为字符。。。为什么


如果您能理解这些问题,我将不胜感激。

wifstream
从文件中读取字节,并使用安装到流的区域设置中的
codevt
facet将其转换为宽字符。默认方面采用系统默认代码页,并对这些字节调用
mbstowcs

要将文件视为UTF-16,您需要使用
codevt\u utf16

std::wifstream-fin(“text.txt”,std::ios::binary);
//应用面
fin.imbue(std::locale(fin.getloc(),
新标准:编解码器(VT_utf16));

wifstream
从文件中读取字节,并使用安装到流的区域设置中的
codevt
facet将其转换为宽字符。默认方面采用系统默认代码页,并对这些字节调用
mbstowcs

要将文件视为UTF-16,您需要使用
codevt\u utf16

std::wifstream-fin(“text.txt”,std::ios::binary);
//应用面
fin.imbue(std::locale(fin.getloc(),
新标准:编解码器(VT_utf16));

我从未听说过注入流,但事实上,这为我遇到的问题提供了解决方案。然而,它引发了另一个问题,我将就此发表文章。非常感谢。为什么要以二进制模式打开文件?@hkBattousai这样,例如,U+0D0A“MALAYALAM字母UU”就不能有效地转换为
\n
。您的意思是0x000A字符将保留为下一行的第一个字符吗?难道我们不能在阅读每一行之后检查它,如果它存在,就把它删除吗?在二进制模式下读取文件并解析行确实是一件让人头疼的事。如果可能的话,我想使用文本模式。@hkBattousai在表示UTF-16编码文本的字节流中,字节0x0D和0x0A有时会以U+0D0A或U+0A0D字符的形式(取决于尾数)或两个字符之间的边界相邻结束。我怀疑在文本模式下打开的流在遇到这样一对字节时,会将它们转换为单个0x0A字节,然后再将字节交给编解码器。那会把一切都搞砸的。(继续)我从未听说过注入溪流,但事实上,这为我所面临的问题提供了解决方案。然而,它引发了另一个问题,我将就此发表文章。非常感谢。为什么要以二进制模式打开文件?@hkBattousai这样,例如,U+0D0A“MALAYALAM字母UU”就不能有效地转换为
\n
。您的意思是0x000A字符将保留为下一行的第一个字符吗?难道我们不能在阅读每一行之后检查它,如果它存在,就把它删除吗?在二进制模式下读取文件并解析行确实是一件让人头疼的事。如果可能的话,我想使用文本模式。@hkBattousai在表示UTF-16编码文本的字节流中,字节0x0D和0x0A有时会以U+0D0A或U+0A0D字符的形式(取决于尾数)或两个字符之间的边界相邻结束。我怀疑在文本模式下打开的流在遇到这样一对字节时,会将它们转换为单个0x0A字节,然后再将字节交给编解码器。那会把一切都搞砸的。(续)
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>));