二进制读取和编写复杂的c++结构

binary reading and writing complicated stucts in c++

本文关键字:c++ 结构 复杂 读取 二进制      更新时间:2023-10-16

我需要在我的项目中保存/读取我的数据结构的能力,但所有的数据都是相当复杂和独特的结构本身的形式,我通常通过其他结构和向量实现。我把它们都包装成一个结构体这样我就有了像

这样的东西
struct master{
    std::vector<apprentice_type1> a;
    std::vector<apprentice_type2> b; //etc.
    std::string label;
};

与其他定义如

struct apprentice_type1{
    vec location;
    int point_label;
    std::vector<int> relational_data;
};
struct vec{
    double x,y,z;
};

所以它变得非常复杂!我拼命地想要一些像

这样的美好,快速和天真的东西
master obj;
//write to obj....
std::ofstream ofs("data.dat", std::ios::binary);
ofs.write((char *)&obj, sizeof(obj));

可能会起作用,但目前似乎不起作用。在我迷失在调试的兔子洞之前,这真的是可能的吗?我接近它的方式,还是我需要重新考虑?如果有,怎么做?

谢谢。

如果您想要一个Boost序列化的替代方案,并且可以访问c++ 11编译器,您也可以查看一下cereal。它的工作方式与Boost序列化几乎相同,但它只是一个头文件库,所以没有什么可链接的

[…还是我需要重新考虑?如果有,怎么做?

你可能需要提供一个完整的实现(即探索"兔子洞")。

这是一个已知的问题(流序列化),并且没有单一的最佳解决方案,因为大多数实现需要解决不同的需求。

你可以这样做:

  • 实现std::i/ostream序列化;这意味着你将复习你的类并实现operator>>(std::istream*, your_type&)和它的逆operator<<(std::ostream*, your_type&)

  • 实现基于流库的序列化(如boost.archive)

  • 使用JSON或XML库。
  • 使用google协议缓冲区(或其他)

  • 根据您的需要滚动您自己的实现。

如果您选择boost::序列化,这里有一个小示例:

#include <fstream>
#include <vector>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/serialization/vector.hpp>

template <typename T>
inline const boost::serialization::nvp<T> archive_value(const char* name, T& value) {
    return boost::serialization::make_nvp(name, value);
}
const unsigned Version = 0;
class Point{
    public:
    double x,y,z;
    private:
    template <typename P, typename Archive>
    static void serialize(P& p, Archive& ar, const unsigned int version) {
        std::cout << "Pointn";
        ar & archive_value("X", p.x);
        ar & archive_value("Y", p.y);
        ar & archive_value("Z", p.z);
    }
    public:
    template <typename Archive>
    void serialize(Archive& ar, const unsigned int version) const {
        serialize(*this, ar, version);
    }
    template <typename Archive>
    void serialize(Archive& ar, const unsigned int version) {
        serialize(*this, ar, version);
    }
};
BOOST_CLASS_VERSION(Point, Version)
struct Scene{
    std::vector<Point> points;
    private:
    template <typename S, typename Archive>
    static void serialize(S& s, Archive& ar, const unsigned int version) {
        std::cout << "Scenen";
        ar & archive_value("Points", s.points);
    }
    public:
    template <typename Archive>
    void serialize(Archive& ar, const unsigned int version) const {
        serialize(*this, ar, version);
    }
    template <typename Archive>
    void serialize(Archive& ar, const unsigned int version) {
        serialize(*this, ar, version);
    }
};
BOOST_CLASS_VERSION(Scene, Version)

template <typename Archive>
void register_types(Archive& ar) {
    ar.template register_type<Point>();
    ar.template register_type<Scene>();
}
int main() {
    Scene scene;
    scene.points = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 } };
    // Output
    {
        std::ofstream out("test.dat", std::ios_base::binary);
        boost::archive::binary_oarchive output(out);

        // First the version!
        output & archive_value("Version", Version);
        // Next the types!
        register_types(output);
        // Finally the data
        output & archive_value("Scene", scene);
    }
    scene.points = {};
    // Input
    {
        int version;
        std::ifstream in("test.dat", std::ios_base::binary);
        boost::archive::binary_iarchive input(in);
        // First the version!
        input & archive_value("Version", Version);
        // Next the types!
        register_types(input);
        // Finally the data
        input & archive_value("Scene", scene);
    }
    for(const auto& p : scene.points)
        std::cout << p.x << 'n';
}

注意:文件格式可能会发生变化,序列化函数(输入和/或输出)可能会根据文件版本进行调整。