提问人:Dan 提问时间:3/5/2014 最后编辑:Dan 更新时间:6/5/2023 访问量:37267
使用 ifstream 将二进制数据读入结构体
Reading binary data into struct with ifstream
问:
我正在尝试使用 ifstream 从文件中读取二进制数据。
具体来说,我正在尝试用从文件中读取的数据填充这个“Header”结构:
struct Header {
char id[16];
int length;
int count;
};
现在,如果我以这种方式读取文件,结果正是我想要的:
input.read((char*)&hdr, sizeof(hdr));
但是,如果我手动读取结构的每个变量,结果是胡言乱语:
input.read((char*)&hdr.id, sizeof(hdr.id)); input.read((char*)&hdr.length, sizeof(hdr.length)); input.read((char*)&hdr.count, sizeof(hdr.count));
我的问题是,这里发生了什么使这两种方法返回不同的结果?
答:
9赞
Blaz Bratanic
3/5/2014
#1
正如上面的评论所述,您可能缺少 hdr.length 和 hdr.count。 我用 gcc 4.8 和 clang 3.5 尝试过,它工作正常。
#include <iostream>
#include <fstream>
#pragma pack(push, r1, 1)
struct Header {
char id[15];
int length;
int count;
};
#pragma pack(pop, r1)
int main() {
Header h = {"alalalala", 5, 10};
std::fstream fh;
fh.open("test.txt", std::fstream::out | std::fstream::binary);
fh.write((char*)&h, sizeof(Header));
fh.close();
fh.open("test.txt", std::fstream::in | std::fstream::binary);
fh.read((char*)&h.id, sizeof(h.id));
fh.read((char*)&h.length, sizeof(h.length));
fh.read((char*)&h.count, sizeof(h.count));
fh.close();
std::cout << h.id << " " << h.length << " " << h.count << std::endl;
}
评论
1赞
WhozCraig
3/5/2014
将字段更改为并再次运行,只是为了踢球。id
char id[15]
0赞
Blaz Bratanic
3/6/2014
你是对的。添加了编译指示以修复对齐方式。
0赞
Jamie
10/22/2021
通过处理字节顺序,这将大大改善。如果这是在大端系统上写的,而在小端系统上阅读,事情会很糟糕。
12赞
Marcel Zebrowski
8/26/2018
#2
也可以一步读取结构。
即fh.read((char*)&h, sizeof(Header));
评论
3赞
Jean-Christophe
7/24/2020
使用此方法时,必须注意避免内存对齐填充。请参阅结构填充和填料
0赞
starriet
9/19/2023
@Jean-Christophe 谢谢,这似乎很重要。您能给我们举一个简单的例子来说明上述代码何时失败吗?相反,接受的答案中的代码似乎存在您提到的问题(结构填充):如果结构是填充的,则由于填充的内存,逐个元素读取一个元素可能会损坏,不是吗?(除非移动位置,包括填充的内存)fstream::read
0赞
Jean-Christophe
10/10/2023
@starriet 这是不可移植的。如果文件最初在不同的指令集上序列化,则上述代码将导致读取损坏。一个典型的情况是从 32 位计算机到 64 位计算机的消息传递。另一种失败情况是读取打包数据上的解压缩结构/标量。
评论
length
count
hdr.length
hdr.count
sizeof(Header)
sizeof(hdr)
sizeof()