2

更新:感谢@Potatoswatter 和@Jonathan Leffler 的评论 - 令人尴尬的是,我被调试器工具提示发现没有正确显示 wstring 的值 - 但是它仍然对我不太有效,我已经更新了问题以下:

如果我有一个小的多字节文件,我想读入一个字符串,我使用以下技巧 - 我使用例如getline分隔符'\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_wide, wchar_t(0) )应该读取整个 unicode 文件。然而事实并非如此——在上面的例子中,我的宽字符串将包含以下两个 wchar_ts:FF FF

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

为什么 wchar_t(0) 不能用作分隔 wchar_t 以便 getline 停止00 00(或读取到我想要的文件末尾)?
谢谢

4

3 回答 3

2

您的 UCS-2 解码器行为异常。getline( inf2, contents_wide )on的结果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 是一些库。

于 2010-04-28T00:11:34.873 回答
1

看到这个问题:为什么 C++ 中的宽文件流默认会缩小写入的数据?,发帖者在写作时对wchar_t->转换感到惊讶。char

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

codecvt是从流的locale. 如果流上没有imbue()-d 区域设置,则使用全局区域设置。默认情况下,全局语言环境是“经典”(或“C”)语言环境。该语言环境的codecvt方面非常基本。我不知道标准对此有何评论,但根据我在 Windows 上的经验,它只是在charand之间“转换” wchar_t,一个接一个。在 Linux 上,它也会这样做,但如果字符的值超出 ASCII 范围,则会失败。

因此,如果您不触及区域设置(通过 -imbue()在流上设置一个或更改全局设置),那么在您的情况下可能发生的情况是chars 从文件中读取并wchar_t 逐个转换为 s 。因此,它首先读取FF,然后FE,然后00,然后getline(..., 0)停在那里。

于 2010-04-28T15:18:13.860 回答
0

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

于 2010-04-28T00:12:48.110 回答