Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ writing an object to a file then later reading it in? [duplicate]

Possible Duplicate:
How to serialize in c++?
How to implement serialization in C++

I've been toying around with C++ more and more these days and have only had a couple experiences with ofstream at this point. Most of said experiences have been doing simple file output of variables and reading them back in with ifstream. What I haven't done is anything with objects.

Let's assume that I have an object that is being written to frequently (say a game, and the object is the character) Every time the character is hit, the hp is re-written, every time they defeat an enemy they are gaining experience.... my basic idea is to write a simple text-based dungeon crawling game. But how am I going to make some kind of an autosave file?? Do I just write out every attribute of my object to a file individually and then move onto bigger and better from there? If I had to do it right now that's how I'd go about doing it, but I can't help like feeling that there's an easier way than that....

Anyone care to help me output the contents of an entire object(and it's respective attributes) to a file?

like image 634
HunderingThooves Avatar asked Oct 12 '11 15:10

HunderingThooves


2 Answers

Here's a hacky trick that will likely get coders here to rip out their hair and scream at me (this only works for static objects and not ones that use dynamic memory allocation):

class TestA
{
    private:
        long Numerics;
        char StaticArray[10];
        int Data[3];

    public:
        TestA(){Numerics = 10; strcpy(StaticArray,"Input data"); Data[0] = 100; Data[1] = 200; Data[2] = 300;}
        void Test(){Numerics = 1000; strcpy(StaticArray,"Data input"); Data[0] = 300; Data[1] = 200; Data[2] = 100;}

        void Print()
        {
            printf("Numerics is: %ld\nStaticArray is: %s\n%d %d %d\n",Numerics,StaticArray,Data[0],Data[1],Data[2]);
        }
};

int main()
{
    TestA Test;
    FILE *File = fopen("File.txt","wb");
    Test.Test();
    Test.Print();
    fwrite((char *)&Test,sizeof(Test),1,File); //Treats the object as if it is a char array
    fclose(File);

    TestA Test2;
    File = fopen("File.txt","rb");
    fread((char *)&Test2,sizeof(Test2),1,File); //Treats the object as if it is a char array
    Test2.Print();
    fclose(File);
    return 0;
}

Which results in:

Numerics is: 1000
Static array is: Data input
300 200 100
Numerics is: 1000
Static array is: Data input
300 200 100

Opening the file reveals the written data:
è Data input w, È d

The above trick allows for easy conversion into a byte-based format. Naturally this is hacky, but classes (or objects) should be expected to supply their own object-to-char array conversion process.

like image 53
SSight3 Avatar answered Oct 26 '22 12:10

SSight3


Take a look at this code :

//! Struct for a 2d marker
struct Marker2d{
    double  x;                    //!< x coordinate of marker in calibration phantom
    double  y;                    //!< y coordinate of marker in calibration phantom
    int     id;                   //!< some unique id (used for sequence id as well as for assigned 3d id)
    int     code;                 //!< type of marker (small = 0, large = 1)
    float   size;                 //!< real size of marker in 2D image (in pixel)
    double  distanceToNearest;    //!< distance to nearest other marker

    /**
    *  Overloaded stream insertion operator. Abbreviation for the output of 2d marker.
    \param  output_out A reference to an std::ostream instance indicating the output stream
    \param  marker_in A constant Marker2d reference indicating the 2d marker that we want to output
    \return a std::ostream reference containing the new output data
    */
    friend std::ostream & operator<<(std::ostream & output_out, const Marker2d & marker_in)
    {
        return output_out<< std::fixed << std::setprecision(15) <<marker_in.x<<"\t"<<marker_in.y<<"\t"<<marker_in.id<<"\t"
        <<marker_in.code<<"\t"<<marker_in.size<<"\t"<<marker_in.distanceToNearest;
    }

    /**
    *  Overloaded stream extraction operator.
    \param  s_in A reference to an std::istream instance indicating the input stream
    \param  marker_out A Marker2d reference indicating the 2d marker that will have its data members populated
    \return a std::istream reference indicating the input stream
    */
    friend std::istream& operator>>(std::istream& s_in, Marker2d & marker_out)
    {
        s_in >> marker_out.x >> marker_out.y >> marker_out.id >> marker_out.code >> marker_out.size >> marker_out.distanceToNearest;
        return s_in;
    }
};

This is a simple struct with overloaded >> and << operators. This allows you to output to a file like myOfstreamFile << obj; And read the other way around.

If you have say, a thousand of objects stored in a file you can simply put them in a container like this :

std::vector<Marker2d> myMarkers;
std::ifstream f( fileName_in.c_str() );
if(!f)
   throw std::exception(std::string("AX.Algorithms.ComputeAssignmentsTest::getMarkersFromFile - Could not open file : " + fileName_in + " for reading!").c_str());

//cool one liner to read objects from file...
std::copy(std::istream_iterator<AX::Calibration::Marker2d>(f), std::istream_iterator<AX::Calibration::Marker2d>(), std::back_inserter(myMarkers));

Of course you could provide other forms of input and output e.g. save to .xml format and parse it as a dom tree etc. This is just a sample.

EDIT : This will work for relatively simple objects. Look at serialization if you need something more complex

like image 29
FailedDev Avatar answered Oct 26 '22 13:10

FailedDev