开发者

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

开发者 https://www.devze.com 2023-04-12 18:29 出处:网络
This question already has answers here: Closed 11 years ago. Possible Duplicate: How to serialize in c++?
This question already has answers here: Closed 11 years ago.

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?


You could just write the object to a file by copying it's contents in memory.

But then you hit the tricky bits! You can't copy any items that are pointers to memory, because when you load them back in they don't own that memory. That means copying things like std::string which may internally contain their own memory allocation is also tricky.

Then even with standard types there are issues if you plan to read them on a different machine with a different number of bits, or a different byte order.

The process is called serialisation - there are a few standard techniques to make it easier.


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


Search the web and SO for "serialization". There are some bumps to watch out for: floating point, endianess and variable length fields (strings).

Good luck!


Behind your simple question hides a complex theme. Please take a look to boost::serialization (here for instance). Any time spent to learning boost it's very rewarding.


There's a nice library in Boost called Boost.Serialize. If you're looking for performance, it is probably not the right choice, but looking at the source code and usage may give you some ideas. Serialization/Deserialization can be tricky, especially when you have lots of nested components. JSON is a very nice format for serializing general objects.


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消