#include <iostream>
#include <fstream>
using namespace std;

class a{
public:
    void set(int x){num = x;}
    int get(){return num;}
private:
    int num;
};

int main(){
    ofstream o_("test.txt");
    o_.close();
    ofstream os("test.txt", ios::binary | **ios::app**);
    a o;
    o.set(1);
    os.write(reinterpret_cast<char*>(&o), sizeof(a) );
//  a o2;
//  o.set(2);
//  os.write(reinterpret_cast<char*>(&o), sizeof(a) );
    os.close();

    a o3,o4;
    ifstream is("test.txt", ios::binary | **ios::app**);
    is.read(reinterpret_cast<char*>(&o3), sizeof(a) );
//  is.read(reinterpret_cast<char*>(&o4), sizeof(a) );

    cout << "o3.get() => " << o3.get() << endl; *//Garbage is Printed*
//  cout << "o4.get() => " << o4.get() << endl;

    return 0;
}

Works fine if I do:

#include <iostream>
#include <fstream>
using namespace std;

class a{
public:
    void set(int x){num = x;}
    int get(){return num;}
private:
    int num;
};

int main(){
    ofstream o_("test.txt");
    o_.close();
    ofstream os("test.txt", ios::binary );
    a o;
    o.set(1);
    os.write(reinterpret_cast<char*>(&o), sizeof(a) );
//  a o2;
//  o.set(2);
//  os.write(reinterpret_cast<char*>(&o), sizeof(a) );
    os.close();

    a o3,o4;
    ifstream is("test.txt", ios::binary );
    is.read(reinterpret_cast<char*>(&o3), sizeof(a) );
//  is.read(reinterpret_cast<char*>(&o4), sizeof(a) );

    cout << "o3.get() => " << o3.get() << endl;
//  cout << "o4.get() => " << o4.get() << endl;

    return 0;
}

Edited 3 Years Ago by MRehanQadri

You cannot open a file in append mode (std::ios::app) to read from it (input). Technically speaking, it doesn't make much sense to open a file for "appended read operations". As far as the C++ standard goes, it says that this is implementation-defined (i.e., will behave differently depending on the system). Some implementations will just ignore the "append mode" request, and open it normally. Some implementations will refuse to open the file (which is what I suspect is happening here). And some implementations will open the file and move the read-position to the end of the file (making the very first read operation hit the "end-of-file" marker). In other words, don't open an input file-stream in append mode.

N.B.: the vagueness comes from the fact that files in different systems (Windows vs. POSIX) behave differently, and there couldn't be a consensus, so it was left as "implementation-defined". In practical terms, it means you can't reliably use it.

When a file is not opened, the read operation leaves the memory unaltered, which explains the "garbage" values that you see (i.e., uninitialized data). Try this:

a o3,o4;
ifstream is("test.txt", ios::binary | ios::app);
if( is ) {
  if( is.read(reinterpret_cast<char*>(&o3), sizeof(a) ) )
    cout << "o3.get() => " << o3.get() << endl;
  else
    cout << "Read operation on input stream failed!" << endl;
} else {
  cout << "Input stream could not be opened!" << endl;
};

My guess is that you will get one of those two error messages to print out.

P.S.: In general, you should not read/write objects directly into a stream via a cast like that. You need to read / write the individual data members. An object can often contain things that cannot be put in a file and recovered later, like pointers, vtable pointers, non-POD data members, etc.. Look into serialization, e.g., the Boost.Serialization library.

Awesome. Thanks a lot, it's really helpful. How to write an object in a file so that it's recoverable properly. I'm going to write each node of a linked list (containing a pointer to next node) to a file (i.e. writing an object each time), and then recover whole object from it. So how will I handle it?

For a linked list, the easiest is probably to save all the nodes (without the pointers) sequentially in the file, and then reconstruct the linked-list when loading the elements.

I suggest you read up the documentation of Boost.Serialization to understand the logic of doing saving/loading of objects. Naively doing is.read(reinterpret_cast<char*>(&o3), sizeof(a) ) is not correct or robust in general, even for primitive types (i.e., because of endianness).

This article has been dead for over six months. Start a new discussion instead.