我尝试在C ++中用二进制文件写入和读取类的对象。我不想单独编写数据成员,而是一次编写整个对象。举个简单的例子:
class MyClass {
public:
int i;
MyClass(int n) : i(n) {}
MyClass() {}
void read(ifstream *in) { in->read((char *) this, sizeof(MyClass)); }
void write(ofstream *out){ out->write((char *) this, sizeof(MyClass));}
};
int main(int argc, char * argv[]) {
ofstream out("/tmp/output");
ifstream in("/tmp/output");
MyClass mm(3);
cout<< mm.i << endl;
mm.write(&out);
MyClass mm2(2);
cout<< mm2.i << endl;
mm2.read(&in);
cout<< mm2.i << endl;
return 0;
}
然而,正在运行的输出显示mm.i的值应该写入二进制文件不会被读取并正确分配给mm2.i
$ ./main
3
2
2
那它有什么问题?
一般在二进制文件中写入或读取类的对象时,我应该注意什么?
答案 0 :(得分:11)
数据正在被缓冲,因此当你去阅读它时它实际上没有到达文件。由于您使用两个不同的对象来引用输入/输出文件,因此操作系统无法确定它们之间的关系。
您需要刷新文件:
mm.write(&out);
out.flush()
或关闭文件(执行隐式刷新):
mm.write(&out);
out.close()
您还可以通过让对象超出范围来关闭文件:
int main()
{
myc mm(3);
{
ofstream out("/tmp/output");
mm.write(&out);
}
...
}
答案 1 :(得分:9)
从多个角度倾倒原始数据是一个可怕的想法。添加指针数据后,这将更加糟糕。
一个建议是使用Boost.Serialization,它允许更强大的数据转储。
您的主要问题是由于fstream缓冲,文件尚未包含内容。关闭或刷新文件。
答案 2 :(得分:2)
我会回应“你不应该这样做”。如果您在上面的代码中打印出sizeof(myc)
它可能是4,正如您所期望的那样......但是尝试将读取和写入更改为虚拟。当我这样做时,它打印出大小为16.这12个字节是具有敏感值的内部内容 - 并将它们保存出来然后将它们读回来就像期望指针值在写入并加载时仍然是好的再一次。
如果要绕过序列化并将C ++对象内存直接映射到磁盘,有很多方法可以解决这个问题。但规则涉及到它并不适合胆小的人。请参阅POST++ (Persistent Object Storage for C++)作为示例。
我要补充一点,您没有检查fail()
或eof()
状态。如果你已经知道你误用了fstream API。再次尝试:
void read(ifstream *in) {
in->read((char *) this, sizeof(myc));
if (in->fail())
cout << "read failed" << endl;
}
void write(ofstream *out){
out->write((char *) this, sizeof(myc));
if (out->fail())
cout << "write failed" << endl;
}
......看看会发生什么。
答案 3 :(得分:1)
我的C ++非常生锈并且严重不足,但您可能需要查看序列化和反序列化。 FAQ
答案 4 :(得分:0)
我使用 output.write((char*)&obj, sizeof(obj))
做了类似的事情,obj 是你的类的一个实例。如果您想在对象内部写入数据,您可能需要循环此操作,通常情况下是这样,因为您需要成员可读,对吗?
使用 read 函数读取也是一样。但是如果您要动态分配这些数据,则需要处理它。