为啥我不能用 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
将保持未初始化状态。但是,如果我改为阅读char
或unsigned 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 的二进制数据?的主要内容,如果未能解决你的问题,请参考以下文章
为啥我不能用字符串为 Dictionary<String, Int> 下标?
为啥我的 List<Foo> 不能用 protobuf-net 序列化?
为啥我不能用 boost::variant 访问这个自定义类型?
鉴于声明,`std::unique<T> p;`,为啥`!p`是合法的,因为`std::unique<T>`没有记忆函数'operator !()'