C ++将一个对象写入一个文件,然后再将其读入?

时间:2011-10-12 15:17:42

标签: c++ serialization object

  

可能重复:
  How to serialize in c++?
  How to implement serialization in C++

这些天我越来越多地使用C ++,并且此时只有一些关于ofstream的经验。大多数所述经验都是对变量进行简单的文件输出,并使用ifstream将其读回。我没有做过的事情就是对象。

让我们假设我有一个经常被写入的对象(比如游戏,对象就是角色)每次击中角色时,每次击败敌人时都会重写hp。获得经验....我的基本想法是编写一个简单的基于文本的地下城爬行游戏。但是我如何制作某种自动保存文件?我是否只是将对象的每个属性单独写入文件,然后从那里移到更大更好的位置?如果我现在必须这样做,那就是我要去做的事情,但我不禁感到有一种比这更简单的方式......

是否有人愿意帮助我将整个对象的内容(以及它各自的属性)输出到文件中?

6 个答案:

答案 0 :(得分:8)

您可以通过将对象的内容复制到内存中来将对象写入文件。

然而你却遇到了棘手的问题!您不能复制指向内存的任何项目,因为当您将它们加载回来时,它们不拥有该内存。这意味着复制像std :: string这样内部包含自己内存分配的东西也很棘手。

然后,即使使用标准类型,如果您计划在具有不同位数或不同字节顺序的其他计算机上读取它们,也会出现问题。

该过程称为serialisation - 有一些标准技术可以使其更容易。

答案 1 :(得分:4)

看看这段代码:

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

这是一个简单的结构,重载了&gt;&gt;和&lt;&lt;运营商。这允许您输出到像myOfstreamFile这样的文件&lt;&lt; OBJ;并反过来阅读。

如果你说,文件中存储了数千个对象,你可以简单地将它们放在这样的容器中:

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

当然,您可以提供其他形式的输入和输出,例如保存为.xml格式并将其解析为dom树等。这只是一个示例。

编辑:这适用于相对简单的对象。如果您需要更复杂的东西,请查看序列化

答案 2 :(得分:3)

搜索网络和SO搜索“序列化”。有一些值得注意的问题:浮点数,字节数和可变长度字段(字符串)。

祝你好运!

答案 3 :(得分:1)

在你的简单问题背后隐藏着一个复杂的主题。请查看boost :: serialization(例如here)。任何花在学习上的时间都会增加它是非常有益的。

答案 4 :(得分:1)

Boost中有一个名为Boost.Serialize的好库。如果您正在寻找性能,它可能不是正确的选择,但查看源代码和用法可能会给您一些想法。序列化/反序列化可能很棘手,尤其是当您有许多嵌套组件时。 JSON是一种用于序列化常规对象的非常好的格式。

答案 5 :(得分:0)

这是一个hacky技巧,可能会让编码员在这里撕掉他们的头发并对我尖叫(这只适用于静态对象而不是使用动态内存分配的那些):

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

结果是:

  

Numerics是:1000
  静态数组是:数据输入
  300 200 100
  数字是:1000
  静态数组是:数据输入
  300 200 100

打开文件会显示书面数据:
è Data input w, È d

上述技巧可以轻松转换为基于字节的格式。当然这是hacky,但应该期望类(或对象)提供自己的对象到字符数组转换过程。