为什么 std::wistream 读取字节宽度字符的 read() 和 get() 方法?

Why the read() and the get() methods of the std::wistream read byte-width character?

提问人:Serge Roussak 提问时间:10/5/2021 更新时间:10/5/2021 访问量:160

问:

我正在尝试获取文件开头是否具有Unicode BOM。我更喜欢使用标准库。我尝试按如下方式解决此任务:iostream

std::wifstream str(filename);
wchar_t bom;
str.get(bom);

我假设由于字符有两个字节大小,此代码应该从文件中读取前两个字节,但它只读取第一个字节。wchar_t0xFF

我知道,这可以通过“普通”流来解决,但我有学术兴趣:为什么给定的代码只返回一个字节?

C++ IOSTREAM C++-标准库

评论

0赞 n. m. could be an AI 10/5/2021
有太多的未知数。您的操作系统、编译器、标准库和文件编码是什么?
0赞 Serge Roussak 10/5/2021
@n.1.8e9-where's-my-sharem。我想,这不应该影响结果,这就是我选择标准库的原因......文件的编码可能是 ANSI 或 Unicode,我需要检测实际的编码。
0赞 n. m. could be an AI 10/5/2021
“Unicode”不是一种编码。“ANSI”不是编码。“不应该”是一个白日梦。我假设你在 Windows 上,这是正确的吗?
0赞 Serge Roussak 10/5/2021
@n.1.8e9-where's-my-sharem。ASCII 和 UTF-16。是的,Windows 和 MSVC。
0赞 n. m. could be an AI 10/5/2021
ASCII 文件没有 BOM。

答:

1赞 n. m. could be an AI 10/5/2021 #1

basic_istream::get尝试从流中读取一个字符,并将其转换为模板化的任何类型。basic_istream

构成流中的字符(流的字符编码)的内容由区域设置决定,而不是由模板化的类型决定。basic_istream

因此,如果需要强制实施 16 位字符编码,则需要在流中为 C++ 区域设置注入 16 位字符编码,而不管它是 还是 .据我所知,Windows 中没有内置的 16 位语言环境。您可以通过添加分面从系统提供的区域设置构造此类 C++ 区域设置,例如:ifstreamwifstreamcodecvt

std::wifstream str(filename);
str.imbue(std::locale(str.getloc(), 
                      new std::codecvt_utf16<wchar_t, 0x10ffff, 
                                             std::codecvt_mode::little_endian>));

如果您的编码是大端序,请跳过。也可以使用 跳过 BOM。std::codecvt_mode::little_endianstd::codecvt_mode::consume_header

std::codecvt_utf16自 C++17 起已弃用,因此如果您决定使用它,则只能靠自己。您还可以构建自己的分面。codecvt

评论

0赞 Serge Roussak 10/5/2021
我知道 ,我已经使用它了。但你回答了另一个问题,不是我的。std::codecvt
0赞 n. m. could be an AI 10/5/2021
添加了与您的问题相关的信息。