闲来无事发现了一个基于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 = ;
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"
}

我的Demo

完整代码如下(或点此下载完整工程,或者从我的github下载包括cereal头文件在内的整个项目):

 #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_=) : 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(, 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 = ;
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 = ;
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 = ;
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 = { , , 3.0 }; SomeData myData();
myData.push(, 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 ;
}

cereal:C++实现的开源序列化库的更多相关文章

  1. 使用C++的开源序列化(Serialization)库cereal

    博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:使用C++的开源序列化(Serialization)库cereal.

  2. C++序列化库的实现

    C++中经常需要用到序列化与反序列化功能,由于C++标准中没有提供此功能,于是就出现了各式各样的序列化库,如boost中的,如谷歌的开源项目,但是很多库都依赖其他库过于严重,导致库变得很庞大.今天来分 ...

  3. DELPHI PROTOBUF免费的开源支持库fundamentals5

    DELPHI PROTOBUF免费的开源支持库fundamentals5 1.源码URL: https://github.com/fundamentalslib/fundamentals5 2.编译P ...

  4. 性能超四倍的高性能.NET二进制序列化库

    二进制序列化在.NET中有很多使用场景,如我们使用分布式缓存时,通常将缓存对象序列化为二进制数据进行缓存,在ASP.NET中,很多中间件(如认证等)也都是用了二进制序列化. 在.NET中我们通常使用S ...

  5. Pugixml一种快速解析XML文件的开源解析库

    Pugixml是一个轻量级的C++ XML开源解析库,DOM形式的解析器.接口和丰富的遍历和修改操作,快速的解析,此外支持XPath1.0实现数据查询,支持unicode编码: 使用Pugixml可通 ...

  6. iOS流行的开源代码库

    本文介绍一些流行的iOS的开源代码库 1.AFNetworking 更新频率高的轻量级的第三方网络库,基于NSURL和NSOperation,支持iOS和OSX.https://github.com/ ...

  7. 从Google开源RE2库学习到的C++测试方案

    最近因为科研需求,一直在研究Google的开源RE2库(正则表达式识别库),库源码体积庞大,用C++写的,对于我这个以前专供Java的人来说真的是一件很痛苦的事,每天只能啃一点点.今天研究了下里面用到 ...

  8. 爆料喽!!!开源日志库Logger的剖析分析

    导读 Logger类提供了多种方法来处理日志活动.上一篇介绍了开源日志库Logger的使用,今天我主要来分析Logger实现的原理. 库的整体架构图 详细剖析 我们从使用的角度来对Logger库抽茧剥 ...

  9. 爆料喽!!!开源日志库Logger的使用秘籍

    日志对于开发来说是非常重要的,不管是调试数据查看.bug问题追踪定位.数据信息收集统计,日常工作运行维护等等,都大量的使用到.今天介绍著名开源日志库Logger的使用,库的地址:https://git ...

随机推荐

  1. (转)create table #temptable 临时表 和 declare @bianliang table ()表变量

    在开发过程中,经常会遇到使用表变量和本地临时表的情况.下面是对二者的一个介绍: 1. 为什么要使用表变量 表变量是从2000开始引入的,微软认为与本地临时表相比,表变量具有如下优点:  a.与其他变量 ...

  2. highcharts插件使用总结和开发中遇到的问题及解决办法

    这里使用的highchart是2014-01-09从官网下载的版本,版本号是3.0.8, 当过了几天后,发现版本号变成了3.0.9,不由得的感叹highchart的版本更新之快. 在jsp中使用hig ...

  3. Django 源码小剖: 初探中间件(middleware)

    因为考虑到文章的长度, 所以 BaseHandler 的展开被推迟了. 在 BaseHandler 中隐藏着中间件的信息, 较常见的 SessionMiddleware 就已经默认安装.  BaseH ...

  4. SQL SERVER 安全性体系

    主体和安全实体 在 SQL Server 2008中,“主体”就是可以访问受保护资源且能获得访问资源所需权限的任何个人.组或流程.与旧版 SQL Server 一样,可以在 Windows 中定义主体 ...

  5. Sql中的Merge和output

    先看merge, 不用merge时: --更新 update TA Value ) --插入没有的数据 insert into TA ,,Value from TB ) and TypeName=@v ...

  6. 谈"自驱力"

    最新说明: 1.标题是为了博眼球取的,请不大家不要纠结具体薪资数字,我瞎取的 2.请注意素质,不要满口喷粪,不要搞人身攻击,尊重别人,就是尊重你自己 3.请大家就事论事,不要胡乱臆想,请站在全局的角度 ...

  7. 数据仓库与ODS的区别

    我在公司的数据部门工作,每天的订单类数据处理流程大致如下: 删除分析数据库的历史订单数据 全量更新订单数据到分析数据库.(由于订单核心数据不大,所以经受得起这么折腾) 将数据简单清洗,并生成数据集市层 ...

  8. 在多线程环境中使用CoreData

    在多线程环境中使用CoreData BY 子非鱼 · 2014 年 10 月 13 日   上回书说道,其实CoreData学起来也没有很复杂,我们其实增删改查都和别的ORM大同小异.但是世界总是很复 ...

  9. 利用闭包向post回调函数传参数

    最近在闲逛XX站的时候,打算搞个破坏,试试有多少人还是用初始密码登陆.比较懒,所以直接打开控制台来写. 所以问题可以描述为: 向后端不断的post数据,id从1~5000自增,后端会根据情况来返回值r ...

  10. win10下LPT并口打印失败和POS打印机的钱箱不能打开,win10的坑

    最近在弄一个收银软件,因为使用到了触摸屏,该PC出厂安装的是老掉牙的XP.SSD固态硬盘,装XP实在是太浪费了.然后尝试了WIN7发现不能激活,然后试win8.1发现比较满意终于觉得配得上触摸屏了,但 ...