使用带有unicode文件的getline的问题

时间:2010-04-27 22:55:14

标签: c++ unicode getline wstring

更新:感谢@Potatoswatter和@Jonathan Leffler的评论 - 相当令人尴尬的是我被调试器工具提示错误地显示了wstring的值 - 但是它仍然不适合我,我有更新了以下问题:

如果我有一个小的多字节文件,我想读取一个字符串,我使用以下技巧 - 我使用getline的{​​{1}}分隔符,例如。

'\0'

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

wstring

例如,我的if unicode文件包含由CRLF分隔的字符A和B,十六进制如下所示:

std::wstring contents_wide;
std::wifstream inf2(L"ucs2-be.txt");
getline( inf2, contents_wide, wchar_t(0) ); //doesn't work

基于以下事实:使用带有'\ 0'的多字节文件getline读取我认为FE FF 00 41 00 0D 00 0A 00 42 应在整个unicode文件中读取的整个文件。但它没有 - 通过上面的示例,我的宽字符串将包含以下两个wchar_ts:getline( inf2, contents_wide, wchar_t(0) )

(如果我删除wchar_t(0),它会按预期读取第一行(即FF FF

为什么wchar_t(0)不能作为分隔wchar_t工作,以便getline在FE FF 00 41 00 0D 00上停止(或读到文件的末尾,这是我想要的)?
谢谢

3 个答案:

答案 0 :(得分:2)

你的UCS-2解码器行为不端。 getline( inf2, contents_wide )上的FE FF 00 41 00 0D 00 0A 00 42结果应为0041 0000 = L"A"。假设您使用的是Windows,则应正确转换行结尾,并且字节顺序标记不应出现在输出中。

建议仔细检查您的操作系统文档,了解如何设置区域设置。

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

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

locale::global( encoding_support::ucs2_bigendian_encoding );

其中encoding_support是某个库。

答案 1 :(得分:1)

请参阅此问题:Why does wide file-stream in C++ narrow written data by default?,海报对wchar_t - >感到惊讶写作时char转换。

该问题的答案也适用于阅读案例。简而言之:在最低级别,文件I / O总是以字节为单位完成。 basic_filebuffstream用于实际执行I / O的内容)使用codecvt构面在“内部”编码(程序看到的字符类型,并使用的字符串)之间进行转换实例化流,在您的情况下wchar_t)和文件的“外部”编码(总是char)。

codecvt是从流locale获得的。如果流上没有区域设置imbue() - d,则使用全局区域设置。默认情况下,全局区域设置是“经典”(或“C”)区域设置。该语言环境的codecvt方面非常基础。我不知道标准对它有什么说法,但是根据我在Windows上的经验,它只是在charwchar_t之间逐个“施放”。在Linux上,它也会这样做但如果字符的值超出ASCII范围则会失败。

因此,如果你没有触及语言环境(通过imbue() - 流上的一个或更改全局一个),你的情况可能会发生char被读取从文件中逐个投射到wchar_t 。因此,它先读取FF,然后是FE,然后是00getline(..., 0)就在那里停止。

答案 2 :(得分:0)

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