将对象信息保存到二进制文件中

时间:2018-09-01 14:13:17

标签: c++

我正在尝试将对象的所有成员变量保存在二进制文件中。但是,成员变量是动态分配的向量。因此,有什么方法可以合并所有数据并将其保存在二进制文件中。到目前为止,它只保存了指针,几乎无济于事。以下是我的运行代码。

#include <vector>
#include <iostream>
#include <fstream>

class BaseSaveFile {

protected:
    std::vector<float> first_vector;

public:
    void fill_vector(std::vector<float> fill) {
        first_vector = fill;
    }

    void show_vector() {
        for ( auto x: first_vector )
        std::cout << x << std::endl;
    }

};


class DerivedSaveFile : public BaseSaveFile {


};


int main ( int argc, char **argv) {

    DerivedSaveFile derived;
    std::vector<float> fill;
    for ( auto i = 0; i < 10; i++) {
        fill.push_back(i);
    }
    derived.fill_vector(fill);
    derived.show_vector();

    std::ofstream save_object("../save_object.bin", std::ios::out | std::ios::binary);
    save_object.write((char*)&derived, sizeof(derived));

}

当前二进制文件的大小仅为24个字节。但是由于10个浮点数的向量,我的执行力要大得多。

2 个答案:

答案 0 :(得分:3)

“有没有办法组合所有数据并将其保存在二进制文件中”-当然可以。您编写代码以遍历所有数据,并将其转换为适合写入文件的形式(您知道如何在回读时解析)。然后,您编写代码以读取文件,将其解析为有意义的变量类,并根据读入的数据构造新对象。没有内置的功能,但这不是火箭科学-只是您需要做的一堆工作/代码。

如果您想使用自己喜欢的搜索引擎查找更多详细信息,则称为序列化/反序列化。

答案 1 :(得分:0)

问题

您可以将对象的确切二进制内容写入文件:

save_object.write((char*)&derived, sizeof(derived));

但是,不能保证您通过反向读取操作将其读回到内存中。这仅适用于具有 trivially copyable type 并且不包含任何指针的一小部分对象。

您可以使用std::is_trivially_copyable<BaseSaveFile>::value验证您的类型是否与该定义匹配,但是我已经可以告诉您,这不是由于向量引起的。

为简化形式定义,普通可复制类型或多或少是仅由其他普通可复制元素和非常基本的数据类型(例如int,float,char或固定大小的数组)组成的类型。

解决方案:序列化简介

通用解决方案,如在其他响应中提到的那样,它称为序列化。但是对于更定制的答案,这是它的外观。

您将在您的类型中添加以下公共方法:

std::ostream& save(std::ostream& os){
    size_t vsize=first_vector.size(); 
    os.write((char*)&vsize, sizeof(vsize));
    os.write((char*)first_vector.data(), vsize*sizeof(float)); 
    return os; 
}

此方法可以访问所有成员,并且可以将它们写入磁盘。对于矢量,首先要记下它的大小(以便以后知道读取文件时知道它的大小)。

然后您将添加相反的方法:

std::istream& load(std::istream& is){
    size_t vsize; 
    if(is.read((char*)&vsize, sizeof(vsize))) {
        first_vector.resize(vsize);
        is.read((char*)first_vector.data(), vsize*sizeof(float)); 
    }
    return is; 
}

这里的诀窍是先读取磁盘上向量的大小,然后在加载向量之前重新调整向量的大小。

请注意istreamostream的使用。这使您可以将数据存储在文件中,但是如果需要,可以使用任何其他类型的流,例如在内存字符串流中。

这里有完整的online example(由于在线服务不提供要写入的文件,因此使用stringstream)。

更多序列化吗?

要了解一些序列化技巧。首先,如果您具有派生类型,则需要将load()save()虚拟化,并为派生类型提供其自己的覆盖版本。

如果您的数据成员之一不可复制,那么它将需要自己的load()save(),然后可以递归调用。或者,您需要自己处理事情,这只有在您可以访问恢复其状态所需的所有成员时才有可能。

最后,您不需要重新发明轮子。外面有一些库可能会有所帮助,例如boost serialisationcereal