C++ 将getline与unicode文件一起使用时出现问题

C++ 将getline与unicode文件一起使用时出现问题,c++,unicode,getline,wstring,C++,Unicode,Getline,Wstring,更新:感谢@Potatoswatter和@Jonathan Leffler的评论-我很尴尬地被调试器工具提示发现没有正确显示WSString的值-但是它仍然对我不起作用,我更新了以下问题: 如果我有一个小的多字节文件,我想读入一个字符串,我使用以下技巧-我使用getline,delimeter为'\0',例如 std::string contents_utf8; std::ifstream inf1("utf8.txt"); getline(inf1, contents_utf8, '\0');

更新:感谢@Potatoswatter和@Jonathan Leffler的评论-我很尴尬地被调试器工具提示发现没有正确显示WSString的值-但是它仍然对我不起作用,我更新了以下问题:

如果我有一个小的多字节文件,我想读入一个字符串,我使用以下技巧-我使用
getline
,delimeter为
'\0'
,例如

std::string contents_utf8;
std::ifstream inf1("utf8.txt");
getline(inf1, contents_utf8, '\0');
这将读取整个文件,包括换行符。
但是,如果我尝试对宽字符文件执行相同的操作,它将不起作用-我的
wstring
只读取到第一行

std::wstring contents_wide;
std::wifstream inf2(L"ucs2-be.txt");
getline( inf2, contents_wide, wchar_t(0) ); //doesn't work
例如,如果我的unicode文件包含由CRLF分隔的字符A和B,十六进制如下所示:

FE FF 00 41 00 0D 00 0A 00 42
基于这样一个事实,即带有“\0”的多字节文件getline读取整个文件,我认为
getline(inf2,contents\u wide,wchar\u t(0))
应该读取整个unicode文件。但是它没有-在上面的示例中,我的宽字符串将包含以下两个wchar\u ts:
FF FF

(如果我删除wchar_t(0),它将按预期读取第一行(即
FE FF 00 41 00 0D 00

为什么wchar\u t(0)不能作为定界wchar\u t工作,以便getline停止在
00
(或者读取到我想要的文件的末尾)?

谢谢

您的UCS-2解码器出现问题。FE FF 00 41 00 0D 00 0A 00 42上的
getline(inf2,contents\u wide)
的结果应该是
0041 0000
=
L“A”
。假设您在Windows上,应该正确转换行尾,并且输出中不应该出现字节顺序标记

建议仔细检查操作系统文档,了解如何设置语言环境

编辑:是否设置了区域设置

locale::global( locale( "something if your system supports UCS-2" ) );

其中编码支持是一些库。

L“ucs2 be.txt”在我看来像是大端字节的标志,但数组FE FF 00 41 00 0D 00 0A 00 42看起来像小端字节。我想这就是为什么FE FF字符被读入数组而不是被跳过的原因。我不明白为什么存在或不存在wchar(0)但是会影响结果。

请参见以下问题:,海报在写作时对
wchar\u t
->
char
转换感到惊讶

这个问题的答案也适用于阅读案例。简言之:在最低级别,文件I/O总是以字节为单位完成的。
basic\u filebuf
(fstream实际执行I/O的内容)使用
codevt
方面在“内部”编码之间进行转换(程序看到的字符类型,用于实例化流,
wchar\u t
,在您的例子中)和文件的“外部”编码(始终是
char

codevt
是从流的
locale
获取的。如果流上没有
imbue()
-d区域设置,则使用全局区域设置。默认情况下,全局区域设置为“经典”(或“C”)区域设置。该区域设置的
codecvt
方面非常基本。我不知道标准对此有何规定,但根据我在Windows上的经验,它只是在
char
wchar\u t
之间逐个“强制转换”。在Linux上,它也会这样做,但如果字符的值超出ASCII范围,则会失败


因此,如果您不接触区域设置(通过
imbue()
-ing流上的区域设置或更改全局区域设置),在您的情况下可能发生的情况是从文件中读取
char
s,并将其逐个转换为
wchar\t
。因此,它首先读取
FF
,然后读取
FE
,然后读取
00
,然后读取
getline(…,0)
就停在那里。

多字节文件应该读到“\n”,不是吗?宽字符版本也是如此-它应该读到宽字符换行符。UCS-2不应该做任何转换,所以它不能是状态机。如果没有任何
\0
的话,它能正常工作吗?@Jonathan Leffler MB文件读到EOF(包括\n)因为我告诉它要停止的delimeter是0@Potatoswatter如果我删除whar_t(0),widechar版本的结果也是一样的-它在第一个0字节处停止读取。@hamish:不,我的意思是如果文件中没有0字节会发生什么。另外,不是“在第一个0字节处停止读取”您要求的是什么?如果您更具体一些,这会很有帮助。它的行为是否像0字节是文件的结尾?这不是您当前的描述听起来的样子。L“ucs2 be.txt”只是文件名。FE FF是big-endian。你是对的,文件名是用来误导人类读者的,但对机器没有影响。但还是有点不对劲。FE FF是big-endian,但后面的都是little-endian。其他的都是big-endian。零在前面,重要的部分在后面。你知道吗他们删除了他们的答案:-)谢谢-最后的评论让我笑了:-)不,我没有设置语言环境-我会尝试一下(但我不明白为什么当参数是wchar_ts时,getline读取的是1字节还是2字节)。我不明白你说的是什么意思“编码支持是一些库”-我只想把一个文件读入wchar\u ts?Potatostater我被卡住了,我不知道该把什么作为区域设置的参数。我想你想让我替换“如果你的系统支持UCS-2的话”"用另一个参数,但我不知道它是不是一个语言名字?使用宽字符的点肯定是避免设置代码页之类的东西吗?我正在运行WiXP SP3。当然C++可以从一个文件中读取W查尔兹,而不是必须指定一个语言。@哈密什:我希望我知道该告诉你什么。我简单地浏览了MSDN的文档。但他们完全专注于国际语言
locale::global( encoding_support::ucs2_bigendian_encoding );