为啥我不能用 operator>> 读取 fstream 的二进制数据?

Posted

技术标签:

【中文标题】为啥我不能用 operator>> 读取 fstream 的二进制数据?【英文标题】:Why can't I read fstream's binary data with operator>>?为什么我不能用 operator>> 读取 fstream 的二进制数据? 【发布时间】:2011-05-08 07:13:12 【问题描述】:

如果我执行以下操作:

ifstream file;
file.open("somefile", ios::binary);

unsigned int data;

file >> data;

我的流将始终设置failbit,而data 将保持未初始化状态。但是,如果我改为阅读charunsigned char,则该流很好。 perror() 告诉我“结果太大”。

我在 Google 上看到的唯一内容是一个建议,说 operator>> 不应该用于二进制数据(更喜欢 read()),但我发现该运算符更简洁且更易于使用 - 它并没有'不需要铸造所有东西。

谁能解释一下这个问题?

【问题讨论】:

【参考方案1】:

iostream extraction operator (>>) 尝试解释由空格分隔的数字字符串,而不是二进制数据。有许多不同的方法可以对二进制形式的无符号整数进行编码(例如,little-endian byte order 中的 32 位 2's complement representation)。这就是为什么您必须使用read/write 函数来操作此类二进制缓冲区的原因。

但是,没有什么能阻止您实现自己的类,以便使用插入和提取运算符以您希望的任何形式序列化二进制数据。这样的类可能会在内部使用 ifstream 对象的读取函数。或者,boost serialization library 可能已经包含您想要的内容。

【讨论】:

【参考方案2】:

应该按照您的描述进行。然而,C++ 标准设计者并不是很优雅。事实上,C++的设计有很多缺陷,甚至C++11和C++14也有很多缺陷。

理想的 C++ 设计应该是:

1.对于文本文件:

ifstream fin_txt("input.txt");
int i;
float j;
double k;
fin_txt >> i >> j >> k;

这将读入3个字符串并解析为整数、浮点数和双精度,并分别存储到i、j和k中。

2.对于二进制文件:

ifstream fin_txt("input.bin", ios::binary);
int i;
float j;
double k;
fin_txt >> i >> j >> k;

这会读入4/8字节(取决于int是32位还是64位)、4字节和8字节二进制数据,分别存入i、j、k。

很遗憾,目前的设计是针对Case 2报错的。或许这可以在C++22中实现。

【讨论】:

您在回答中得到了这种方式的原因:“取决于 int 是 32 位还是 64 位”。目前,使用<iostreams> 的代码是可移植的,您的建议不是。 致@Caleth,好吧,正如我所说,这是标准 C++ 中的另一个设计缺陷,它应该区分 int32 和 int64 而不仅仅是 int,它可以是 32 位或 64 位,将来可能是 128 位。 int 的字段大小确定性与其他的不同(char=8-bits, long=32-bits, long long=64-bits, float=32-bits, double=64-bits)。为了解决这个问题,我们可以简单地分别定义 int32 和 int64,如果给二进制文件一个字段大小非确定性类型,即 fin_txt >> i; 则会抛出运行时错误。 // 抛出错误,fin_txt >> (int32)i; // 正确编译 这不是ios::binary(和ios::text)的用途。一些平台在“文本模式”和“二进制模式”之间区分它们如何呈现带有行结束字符的文件。 ios 标志处理。 @Caleth 那么可能有一个带有操作符的文本流>>和>作为二进制写入完成

以上是关于为啥我不能用 operator>> 读取 fstream 的二进制数据?的主要内容,如果未能解决你的问题,请参考以下文章

为啥派生类不能继承operator =()函数[重复]

为啥我不能用字符串为 Dictionary<String, Int> 下标?

为啥我的 List<Foo> 不能用 protobuf-net 序列化?

为啥我不能用 boost::variant 访问这个自定义类型?

鉴于声明,`std::unique<T> p;`,为啥`!p`是合法的,因为`std::unique<T>`没有记忆函数'operator !()'

为啥我不能用相同的参数类型组合两个不同的函数?