[转]cereal:C++实现的开源序列化库

文章转载自https://www.cnblogs.com/lidabo/p/8143664.html

闲来无事发现了一个基于C++实现的序列化工具,相比于其他(比如Boost serialization或Google protobuf,恰巧都用过,以后再介绍),使用简单,感觉不错,下面做个摸索。

cereal介绍

cereal是一个开源的(BSD License)、轻量级的、支持C++11特性的、仅仅包含头文件实现的、跨平台的C++序列化库。它可以将任意的数据类型序列化成不同的表现形式,比如二进制、XML格式或JSON。cereal的设计目标是快速、轻量级、易扩展——它没有外部的依赖关系,而且可以很容易的和其他代码封装在一块或者单独使用。

cereal支持标准库的几乎每一个类型的序列化。cereal也完全支持继承和多态。由于cereal被设计为一个精简、快速的库,它不像其他序列化库(比如Boost)在同一层次上会进行对象跟踪,这也导致了它不支持原始指针(raw pointer)和引用,但是智能指针(比如std::shared_ptr和std​​::unique_ptr)是没有问题的。

cereal适用于基于C++11标准的各种编译器 
cereal使用了一些C++11的新特性,因此需要一个兼容性更好的的C++编译器才能正常工作。已被验证可用的编译器有g++4.7.3、clang++3.3、MSVC2013,或者更新版本。
它也可能可以在老版本编译器上工作,但并不保证完全支持。当使用g++或clang++编译器时,cereal同时需要libstdc++和libc++库。 
 
cereal:更快速,更好的压缩
在简单的性能测试中,cereal通常比Boost的序列化库速度更快,而且产生的二进制形式占用更少的空间,尤其是针对更小的对象。cereal使用了C++中的速度最快的XMLJSON解析器和包装器。
 
cereal是可扩展的 
cereal提供了对标准库的序列化支持,比如二进制的,XML和JSON序列化器。
cereal的源代码相比Boost来讲,更容易理解和扩展。 如果你需要别的东西,cereal可以很容易地扩展,比如添加自定义序列化存档或类型。

cereal是易于使用的 
在代码增加cereal序列化功能可以简化为包含一个头文件,写一个序列化函数。无论是从概念上还是代码层次上,cereal的功能都是自文档化的。
如果你使用错误,cereal尽可能的在编译期触发静态断言。

对于Boost使用者来说,cereal提供了相似的语法,如果你使用过Boost的序列化库,你会发现cereal的语法看起来很熟悉。

如果你是从Boost转向使用cereal,一定要阅读这个过渡指南:http://uscilab.github.io/cereal/transition_from_boost.html

简单的使用 

好吧,废话就这么多,先上一个简单的事例:

std::ofstream os("my.xml");
cereal::XMLOutputArchive archive(os);
int age = 26;
std::string name = "lizheng";
archive(CEREAL_NVP(age), cereal::make_nvp("Name", name));

以上代码完成了对一个int类型和string类型的xml序列化实现。结果如下:

<?xml version="1.0" encoding="utf-8"?>
<cereal>
    <age>26</age>
    <Name>lizheng</Name>
</cereal>

注意上面代码中的cereal::XMLOutputArchive,其实还有针对JSON、二进制序列化的类,如果是序列化为JSON串,结果如下(代码在最下面):

{
    "age": 26,
    "Name": "lizheng"
}
#include <iostream>
#include <fstream>
#include <string>
#include "cereal/archives/binary.hpp"
#include "cereal/archives/xml.hpp"
#include "cereal/archives/json.hpp"
#include "cereal/types/unordered_map.hpp"
#include "cereal/types/memory.hpp"
#include "cereal/types/string.hpp"  //一定要包含此文件,否则无法将std::string序列化为二进制形式,请看:https://github.com/USCiLab/cereal/issues/58

using namespace std;

struct MyRecord
{
    int x, y;
    float z;

    template <class Archive>
    void serialize(Archive & ar)
    {
        ar(x, y, z);
    }

    friend std::ostream& operator<<(std::ostream& os, const MyRecord& mr);
};

std::ostream& operator<<(std::ostream& os, const MyRecord& mr)
{
    os << "MyRecord(" << mr.x << ", " << mr.y << "," << mr.z << ")\n";
    return os;
}

struct SomeData
{
    int32_t id;
    std::shared_ptr<std::unordered_map<uint32_t, MyRecord>> data;

    SomeData(int32_t id_=0) : id(id_), data(new std::unordered_map<uint32_t, MyRecord>)
    {
        
    }

    template <class Archive>
    void save(Archive & ar) const
    {
        ar(id, data);
    }

    template <class Archive>
    void load(Archive & ar)
    {
        ar(id, data);
    }

    void push(uint32_t, const MyRecord& mr)
    {
        data->insert(std::make_pair(100, mr));
    }

    void print()
    {
        std::cout << "ID : " << id << "\n";
        if (data->empty())
            return;
        for (auto& item : *data)
        {
            std::cout << item.first << "\t" << item.second << "\n";
        }
    }
};

void Serialization_XML()
{
    {
        std::ofstream os("my.xml");

        cereal::XMLOutputArchive archive(os);

        int age = 26;
        std::string name = "lizheng";

        //#define CEREAL_NVP(T) ::cereal::make_nvp(#T, T)
        archive(CEREAL_NVP(age), cereal::make_nvp("Name", name));

        //os.close();  //注意:这里不能显示关闭ofstream,否则序列化无法写入到文件
    }

    {
        std::ifstream is("my.xml");
        cereal::XMLInputArchive archive(is);

        int age;
        std::string name;

        archive(age, name);
        std::cout << "Age: " << age << "\n" << "Name: " << name << "\n";
    }
}

void Serialization_JSON()
{
    {
        std::ofstream os("my.json");
        cereal::JSONOutputArchive archive(os);

        int age = 26;
        std::string name = "lizheng";

        archive(CEREAL_NVP(age), cereal::make_nvp("Name", name));
    }

    {
        std::ifstream is("my.json");
        cereal::JSONInputArchive archive(is);

        int age;
        std::string name;

        archive(age, name);
        std::cout << "Age: " << age << "\n" << "Name: " << name << "\n";
    }
}


void Serialization_Binary()
{
    {
        std::ofstream os("my.binary", std::ios::binary);
        cereal::BinaryOutputArchive archive(os);
        
        int age = 26;
        std::string name = "lizheng";

        archive(CEREAL_NVP(age), CEREAL_NVP(name));
    }
    {
        std::ifstream is("my.binary", std::ios::binary);
        cereal::BinaryInputArchive archive(is);

        int age;
        std::string name;

        archive(age, name);
        std::cout << "Age: " << age << "\n" << "Name: " << name << "\n";
    }
}

void Serialization_Obj()
{
    {
        std::ofstream os("obj.cereal", std::ios::binary);
        cereal::BinaryOutputArchive archive(os);

        MyRecord mr = { 1, 2, 3.0 };

        SomeData myData(1111);
        myData.push(100, mr);
    
        archive(myData);
    }
    {
        std::ifstream is("obj.cereal", std::ios::binary);
        cereal::BinaryInputArchive archive(is);

        SomeData myData;
        archive(myData);
        myData.print();
    }
}


int main()
{
    Serialization_XML();     std::cout << "----------------------\n";

    Serialization_JSON();    std::cout << "----------------------\n";

    Serialization_Binary();  std::cout << "----------------------\n";

    Serialization_Obj();     std::cout << "----------------------\n";

    getchar();
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值