0%

C/C++编程—序列化库Cereal

Cereal是一个开源的、轻量级的跨平台序列化库。cereal只包含头文件,不依赖任何三方库,易于使用。Cereal可以将任意的数据类型序列化成二进制、XML格式或者JSON。

Cereal使用非常简单,只需要包含头文件以及为需要序列化的数据编写一个序列化函数即可,会寻找定义在数据结构中serialization函数。使用Cereal进行序列化主要分为两个步骤:定义对象数据的序列化函数,以及对象数据的序列化

1. Cereal序列化函数

Cereal支持单独使用serialization函数,或者分别使用load/save函数进行序列化。序列化函数既可以定义在数据的外部,也可以定义在内部。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
#include <string>

/*内部serialization函数*/
struct Student
{
std::string name;
int age;

template<calss Archive>
void serialize(Archive &archive)
{
archive(name, age);
}
};

/*外部serialization函数*/
struct Student
{
std::string name;
int age;
};
template<calss Archive>
void serialize(Archive &archive, Student &stu)
{
archive(stu.name, stu.age);
}

NOTE:序列化函数也可以私有化,但是必须声明Cereal为友元,因为序列函数私有化之后无法从外部访问,只能通过cereal::access进行访问。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <cereal\access.hpp> // 必须
class Student
{
friend class cereal::access; // 必须

private:
template<calss Archive>
void serialize(Archive &archive) // 私有函数,无法从外部访问
{
archive(name, age);
}

std::string name;
int age;
}

NOTE:如果使用load/save函数进行序列化,save函数必须是const类型,否则Cereal会报错。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
#include <string>

/*内部serialization函数*/
struct Student
{
std::string name;
int age;

template<calss Archive>
void save(Archive &archive) const // const
{
archive(name, age);
}
template<calss Archive>
void load(Archive &archive)
{
archive(name, age);
}
};

/*外部serialization函数*/
struct Student
{
std::string name;
int age;
};
template<calss Archive>
void save(Archive &archive, Student const &stu) // const
{
archive(stu.name, stu.age);
}
template<calss Archive>
void save(Archive &archive, Student &stu)
{
archive(stu.name, stu.age);
}

2. Cereal数据序列化

Cereal支持二进制、XML和JSON三种格式的读写操作,在使用时包含对应的头文件。

1
2
3
4
#include <cereal\archives\binary.hpp> // 二进制
#include <cereal\archives\portable_binary.hpp> // 顺序二进制
#include <cereal\archives\xml.hpp>
#include <cereal\archives\json.hpp>

Cereal的读写操作是基于C++的std::ostream和std::istream。这意味着,操作对象可以是文件、内存流,甚至标准的输入输出。以下代码实现的是对cv::Mat序列化,序列化函数为Serialising OpenCV matrices using boost and cereal

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <sstream>

#include <cereal\archives\binary.hpp>

#include <opencv2\core.hpp>
#include <opencv2\highgui.hpp>

#include "matserialization.h"

#ifdef _DEBUG
#pragma comment(lib,"opencv_world346d.lib")
#else
#pragma comment(lib,"opencv_world346.lib")
#endif

int main()
{
cv::Mat image = cv::imread("../../data/imgs/panda.bmp", cv::IMREAD_GRAYSCALE);
std::stringstream str;
{ // 使用大括号来限定序列化类的生存范围
cereal::BinaryOutputArchive oarchive(str);
oarchive(image);
} // Cereal存储类自动销毁,完成序列化操作
cv::Mat image_loaded;
{
cereal::BinaryInputArchive iarchive(str);
iarchive(image_loaded);
}

system("pause");
return 0;
}

NOTE:Cereal的工作方式是RAII规范,即只有在存储类被销毁时,才能完全保证完全输出。

3. Cereal与boost.Serialization

Cereal和Boost很相似。这是因为Cereal被设计时就考虑了Boost用户的使用习惯,模仿了许多Boost序列化库的语法习惯。Cereal和Boost序列库的接口非常相似,在一些情况下可以非常迅速的将Boost库替换成Cereal。但是即便如此,Cereal和Boost还是有很大的区别。

  • cereal在保存数据时会存储尽可能少的元数据。 Boost默认情况下会存储有关库版本以及类型本身的各种元数据。
  • cereal只需要头文件,不依赖任何三方库或者平台。boost的库非常多,而且需要考虑不同机器之间的版本问题。
  • cereal支持几乎所有的标准库,cereal支持而boost不支持的包括:<forward_list><memory><queue><stack><tuple><unordered_set><unordered_map>
  • cereal更加简洁。例如,在Cereal中当把serialize函数分成load/save函数时,不需要提前使用宏声明。Cereal还使用了static_assert,提供了更加准确的错误提示。
  • cereal和boost使用不同的语法进行序列化。boost使用的是&<<>>,cereal使用的是()

参考文献 & 资源链接