【问题标题】:Write and read object of class into and from binary file将类的对象写入和读取二进制文件
【发布时间】:2010-01-12 05:08:07
【问题描述】:

我尝试在 C++ 中将类对象写入和读取二进制文件。我不想单独编写数据成员,而是一次编写整个对象。举个简单的例子:

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

但是运行输出显示,应该写入二进制文件的 mm.i 的值没有被读取并正确分配给 mm2.i

$ ./main   
3  
2  
2  

那有什么问题呢?

一般在二进制文件中写入或读取类的对象时应注意什么?

【问题讨论】:

    标签: c++ file


    【解决方案1】:

    数据正在被缓冲,所以当你去读取它时它实际上并没有到达文件。由于您使用两个不同的对象来引用输入/输出文件,因此操作系统不知道它们之间的关系。

    您需要刷新文件:

    mm.write(&out);
    out.flush()
    

    或关闭文件(执行隐式刷新):

    mm.write(&out); 
    out.close()
    

    您也可以通过让对象超出范围来关闭文件:

    int main()
    {
        myc mm(3);
    
        {
            ofstream out("/tmp/output");
            mm.write(&out); 
        }
    
        ...
    }
    

    【讨论】:

    • 谢谢!是否可以在 C++ 中为文件写入和读取定义一个对象?我记得在 C 中是可能的。
    • @蒂姆。是的,您可以打开文件流进行读写。
    • 在我看来,Yann Ramin 的回答更有用。他解释了这个冲洗的想法,并且还指出了使用 boost 的更好方法。
    【解决方案2】:

    从多个角度来看,转储原始数据是一个糟糕的主意。一旦添加了指针数据,情况就会变得更糟。

    一个建议是使用Boost.Serialization,它允许更强大的数据转储。

    您的主要问题是由于 fstream 缓冲,文件尚不包含内容。关闭或刷新文件。

    【讨论】:

      【解决方案3】:

      我会回应“你不应该这样做”。如果您在上面的代码中打印出sizeof(myc),它可能是 4,正如您所期望的那样......但是尝试将读写更改为虚拟。当我这样做时,它会打印出大小为 16。这 12 个字节是具有敏感值的内部内容 - 将它们保存出来然后读回它们就像期望指针值在你编写并加载它时仍然很好再来一遍。

      如果您想绕过序列化并将 C++ 对象内存直接映射到磁盘,有一些方法可以破解它。但是涉及规则,这不适合胆小的人。以POST++ (Persistent Object Storage for C++) 为例。

      我要补充一点,您没有检查 fail() 或 eof() 状态。如果你知道你在滥用 fstream API。再试一次:

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

      ...看看会发生什么。

      【讨论】:

        【解决方案4】:

        我的 C++ 相当生锈,并且测试不足,但您可能想看看序列化和反序列化。 FAQ

        【讨论】:

          【解决方案5】:

          我使用output.write((char*)&amp;obj, sizeof(obj)) 做了类似的事情,obj 是你的类的一个实例。如果您想在对象中写入数据,您可能需要循环这个,通常情况下您需要成员可读,对吧?

          使用读取功能进行读取也是如此。但是如果你有动态分配来处理这些数据,你需要处理它。

          【讨论】:

            猜你喜欢
            • 2023-03-23
            • 2014-09-25
            • 2015-07-03
            • 1970-01-01
            • 1970-01-01
            • 2014-01-07
            • 2015-06-16
            • 1970-01-01
            相关资源
            最近更新 更多