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

问题描述 投票:1回答:2

我试图在二进制文件中保存对象的所有成员变量。但是,成员变量是动态分配的向量。那么,有没有办法将所有数据组合起来并将其保存在二进制文件中。截至目前,它只是保存指针,这没什么帮助。以下是我的运行代码。

#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个浮点数的向量,我的数据量要大得多。

c++
2个回答
3
投票

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

它被称为序列化/反序列化btw,以防您想使用您首选的搜索引擎查找更多详细信息。


0
投票

The problem

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

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

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

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

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

The solution: introduction to serialization

一般解决方案,如其他响应中所提到的,它称为序列化。但是对于更加量身定制的答案,这就是它的样子。

您可以将以下公共方法添加到您的类型:

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,因为在线服务不提供要写入的文件)。

More serialization ?

有一些序列化技巧要知道。首先,如果你有派生类型,你需要使load()save()虚拟,并为派生类型提供自己的重写版本。

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

最后,您不需要重新发明轮子。外面有一些图书馆可能有所帮助,比如boost serialisationcereal

© www.soinside.com 2019 - 2024. All rights reserved.