简体   繁体   中英

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++. 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

$ ./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.

Your main problem is the file does not contain the contents yet due to fstream buffering. 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. 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.

If you want to circumvent serialization and map C++ object memory directly to disk, there are ways to hack that. But rules are involved and it's not for the faint of heart. See POST++ (Persistent Object Storage for C++) as an example.

I'll add that you did not check the fail() or eof() status. If you had you'd have known you were misusing the 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. FAQ

I've done something similar using output.write((char*)&obj, sizeof(obj)) , obj being an instance of your class. 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. But if you have dynamic allocation to do then with this data, you need to handle it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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