简体   繁体   English

在二进制文件中写入和读取类的对象

[英]Write and read object of class into and from binary file

I try to write and read object of class into and from binary file in C++.我尝试在 C++ 中将类的对象写入和读取到二进制文件中。 I want to not write the data member individually but write the whole object at one time.我不想单独写入数据成员,而是一次写入整个对象。 For a simple example:举个简单的例子:

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;  
}

However the running output show that the value of mm.i supposedly written to the binary file is not read and assigned to mm2.i correctly然而,运行输出显示应该写入二进制文件的 mm.i 的值未被读取并正确分配给 mm2.i

$ ./main   
3  
2  
2  

So what's wrong with it?那么它有什么问题呢?

What shall I be aware of when generally writing or reading an object of a class into or from a binary file?通常在二进制文件中写入或读取类的对象时,我应该注意什么?

The data is being buffered so it hasn't actually reached the file when you go to read it.数据正在缓冲,因此在您读取文件时它实际上并未到达文件。 Since you using two different objects to reference the in/out file, the OS has not clue how they are related.由于您使用两个不同的对象来引用输入/输出文件,因此操作系统不知道它们之间的关系。

You need to either flush the file:您需要刷新文件:

mm.write(&out);
out.flush()

or close the file (which does an implicit flush):或关闭文件(执行隐式刷新):

mm.write(&out); 
out.close()

You can also close the file by having the object go out of scope:您还可以通过让对象超出范围来关闭文件:

int main()
{
    myc mm(3);

    {
        ofstream out("/tmp/output");
        mm.write(&out); 
    }

    ...
}

Dumping raw data is a terrible idea, from multiple angles.从多个角度来看,转储原始数据是一个糟糕的主意。 This will break even worse once you add pointer data.一旦您添加指针数据,这将变得更糟。

One suggestion would be to use Boost.Serialization which allows for far more robust data dumping.一个建议是使用Boost.Serialization ,它允许更强大的数据转储。

Your main problem is the file does not contain the contents yet due to fstream buffering.您的主要问题是由于 fstream 缓冲,该文件尚不包含内容。 Close or flush the file.关闭或刷新文件。

I'll echo "you shouldn't be doing this".我会回应“你不应该这样做”。 If you print out sizeof(myc) in the code above it's probably 4, as you'd expect... BUT try changing read and write to be virtual.如果您在上面的代码中打印出sizeof(myc)它可能是 4,正如您所期望的那样......但是尝试将读取和写入更改为虚拟。 When I did so, it prints out the size as 16. Those 12 bytes are internal guts with sensitive values—and saving them out and then reading them back in would be like expecting a pointer value to be still good if you wrote it and loaded it again.当我这样做时,它会打印出大小为 16。这 12 个字节是带有敏感值的内部数据——将它们保存出来然后读回它们就像期望一个指针值仍然是好的,如果你写了它并加载了它再说一遍。

If you want to circumvent serialization and map C++ object memory directly to disk, there are ways to hack that.如果你想绕过序列化并将 C++ 对象内存直接映射到磁盘,有一些方法可以破解。 But rules are involved and it's not for the faint of heart.但是涉及规则,它不适合胆小的人。 See POST++ (Persistent Object Storage for C++) as an example.POST++(C++ 的持久对象存储)为例。

I'll add that you did not check the fail() or eof() status.我要补充一点,您没有检查fail()eof()状态。 If you had you'd have known you were misusing the fstream API.如果你知道,你就会知道你在滥用 fstream API。 Try it again with:再试一次:

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;
}

...and see what happens. ...看看会发生什么。

My C++ is pretty rust and highly under-tested, but you may want to take a look at Serialization and Unserialization.我的 C++ 非常生疏,而且未经充分测试,但您可能想看看序列化和反序列化。 FAQ常问问题

I've done something similar using output.write((char*)&obj, sizeof(obj)) , obj being an instance of your class.我使用output.write((char*)&obj, sizeof(obj))做了类似的事情,obj 是你的类的一个实例。 You may want to loop this if you want to write the data inside the object instead, which would generally be the case as you need members to be readable, right ?如果您想将数据写入对象内部,您可能想要循环此操作,通常情况下是这样,因为您需要成员可读,对吗?

Same thing for reading with read function.使用 read 功能阅读也是如此。 But if you have dynamic allocation to do then with this data, you need to handle it.但是,如果您要动态分配这些数据,则需要处理它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM