【问题标题】:Why the read() and the get() methods of the std::wistream read byte-width character?为什么 std::wistream 的 read() 和 get() 方法读取字节宽度字符?
【发布时间】:2021-11-25 14:36:07
【问题描述】:

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

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

我假设因为 wchar_t 字符有两个字节大小,这段代码应该从文件中读取前两个字节,但它只读取第一个 0xFF 字节。

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

【问题讨论】:

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

标签: c++ iostream c++-standard-library


【解决方案1】:

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

流中字符的构成(流的字符编码)由语言环境决定,而不是由模板化的basic_istream 类型决定。

因此,如果您需要强制使用 16 位字符编码,则需要在流中为 C++ 语言环境注入 16 位字符编码,无论是ifstream 还是wifstream。据我所知,Windows 中没有内置 16 位语言环境。您可以通过添加codecvt facet 从系统提供的语言环境构建此类 C++ 语言环境,例如:

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

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

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

【讨论】:

  • 我知道std::codecvt,并且已经在使用它。但你回答了另一个问题,不是我的。
  • 添加了与您的问题相关的信息。
猜你喜欢
  • 1970-01-01
  • 2022-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-22
  • 2013-07-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多