更新:感谢@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
上停止(或读到文件的末尾,这是我想要的)?
谢谢
答案 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_filebuf
(fstream
用于实际执行I / O的内容)使用codecvt
构面在“内部”编码(程序看到的字符类型,并使用的字符串)之间进行转换实例化流,在您的情况下wchar_t
)和文件的“外部”编码(总是char
)。
codecvt
是从流locale
获得的。如果流上没有区域设置imbue()
- d,则使用全局区域设置。默认情况下,全局区域设置是“经典”(或“C”)区域设置。该语言环境的codecvt
方面非常基础。我不知道标准对它有什么说法,但是根据我在Windows上的经验,它只是在char
和wchar_t
之间逐个“施放”。在Linux上,它也会这样做但如果字符的值超出ASCII范围则会失败。
因此,如果你没有触及语言环境(通过imbue()
- 流上的一个或更改全局一个),你的情况可能会发生char
被读取从文件中逐个投射到wchar_t
。因此,它先读取FF
,然后是FE
,然后是00
,getline(..., 0)
就在那里停止。
答案 2 :(得分:0)
L“ucs2-be.txt”在我看来就像大端的标志,但数组FE FF 00 41 00 0D 00 0A 00 42看起来像小端。我想这就是FE FF字符被读入你的数组而不是被跳过的原因。我无法弄清楚为什么wchar(0)的存在与否会影响结果。