C++ 中的序列化库
在本文中,您将了解不同的 C++ 序列化库。
首先,我们将了解序列化及其在 C++ 中的用途。 接下来,我们将讨论 C++ 中的序列化库以及如何在我们的程序中使用它们。
序列化概述
程序员经常使用内存中的数据对象。 有时,对象必须通过网络发送或写入持久存储(通常是文件)以保存程序状态的某些部分。
序列化是将数据或对象状态转换为二进制格式的过程/技术。 二进制形式是用于存储/保留对象状态或通过计算机网络将其传输到内存、数据库、文件或磁盘的字节流。
序列化过程的逆过程称为反序列化。 当您想要在程序执行期间或之后维护结构化数据(即 C++ 类或结构)的状态时,序列化非常适合。
您可以通过本网站上的示例了解 serialize() 和 deserialize()。
序列化提供了软件对象值的稳定字节表示。 然后,这些字节可以通过网络发送,即使在未来使用不同的硬件和软件的实现中,该网络也将继续正常工作。
各种语言的连载
在继续之前,序列化过程在不同语言中的实现方式有所不同。 下面让我们来探讨一下。
- 在Java中,序列化方法是writeObject,它在ObjectOutputStream中实现。
- 在Python中,序列化方法是pickle.dumps()。
- 在 Ruby 中,序列化方法是 marshal.dump()。
- 在C++中,方法是boost::archive::text_oarchive a (filename); 一个<<数据; 调用序列化方法
- 在MFC(微软基础类库)中,序列化方法是:从CObject驱动你的类。
我们的主要关注点是 C++ 序列化,所以让我们看看它是如何工作的。
C++ Boost.Serialization 使用文本存档对象。 序列化写入作为输出数据流运行的输出归档对象。
当针对类数据类型调用时,>> 输出运算符调用类来序列化函数。 每个序列化函数都使用 & 运算符,或通过 >> 递归序列化嵌套对象以保存或加载其数据成员。
为了更好地理解 C++ 中的序列化,您可以查看此网站。
C++ 中的序列化库
C++ 提供了许多用于序列化的库(Boost 序列化除外)。 所有库都有助于实现高序列化性能,因此让我们探索其中一些。
Protocol
Protocol Buffers (Protobufs),一种用于序列化数据的跨平台。 它有助于程序之间通过网络进行通信。
Protobuf序列化机制是通过协议应用给出的。 该编译器将解析 .proto 文件,并根据其参数配置的语言(在本例中为 C++)生成源文件作为输出。
您可以阅读此链接上的教程以更好地了解 Protobuf。
FlatBuffers
FlatBuffers 是一个开源跨平台,用于实现最大内存效率。 您可以直接访问序列化数据,无需解析它,具有前向/后向兼容性。
使用 FlatBuffers,首先使用 --CPP 选项生成 C++ 模式。 然后,您可以在文件中包含 Flatbuffer 来读取或写入此生成的代码。
您可以在此链接中找到使用 FlatBuffers 的序列化实现。
Cereal
Cereal 是仅包含头文件的 C++ 11 序列化库。 Cereal 接受任意数据类型,并将它们可逆地转换为不同的表示形式,例如紧凑的二进制编码、XML 或 JSON。
Cereal 是可扩展的、快速的、经过单元测试的,并提供类似 Boost 的熟悉语法。 要下载完整的谷物食品库,请单击此处。
接下来,我们有一个示例来展示谷物库的使用:
#include <cereal/types/unordered_map.hpp>
#include <cereal/types/memory.hpp>
#include <cereal/archives/binary.hpp>
#include <fstream>
struct MyRecord{
uint8_t x, y;
float z;
template <class Archive>
void serialize( Archive & ar ){
ar( x, y, z );
}
};
struct SomeData{
int32_t id;
std::shared_ptr<std::unordered_map<uint32_t, MyRecord>> data;
template <class Archive>
void save( Archive & ar ) const{
ar( data );
}
template <class Archive>
void load( Archive & ar ){
static int32_t idGen = 0;
id = idGen++;
ar( data );
}
};
int main(){
std::ofstream out("out.cereal", std::ios::binary);
cereal::BinaryOutputArchive archive( out );
SomeData myData;
archive( myData );
return 0;
}
在主函数中,我们以二进制模式创建一个名为 os.cereal 的二进制文件。
在下面的行中,我们从在谷物库的 archives 文件夹中定义的 binary.hpp 创建 BinaryOutputArchive 类的对象。 我们将文件对象传递给 BinaryOutputArchive 的构造函数。
接下来,我们创建要序列化的数据对象,类一些数据的对象。 最后,在主函数的第四行中,我们将数据对象传递给存档,间接调用 save 函数将数据保存在输出文件中,以将序列化对象保存在输出文件 out.cereal 中。
二进制文件 out.cereal 包含我们的序列化数据。 此代码的输出将是文件 out.cereal 中的数据。
这些数据是二进制形式的,我们可以使用不同操作系统中可用的不同实用程序/命令来检查它。
HPS
HPS 是一种高性能仿真工具,是 C++11 中用于数据序列化的纯头文件库。 HPS 将您的数据编码为压缩格式,以便轻松通过网络传递。
HPS 比 C++ 中的普通 boost 序列化快 150%,因为它只需要一行用于标准模板库和原始数据类型的代码。
您还可以使用 write to_stream 和 from_stream 函数来读取和写入文件中的数据。 为了更好地了解HPS,您还可以访问该网站。
GitHub 消息包
MessagePack 是一种特定于开源的序列化格式。 您可以轻松地交换 JSON 和 XML 等不同格式的数据。
整数值只需要一个字节来编码数据,而字符串值需要一个额外的字节。
要进一步实现 msgpack,您可以访问该链接。
Boost.Serialization
C++ 中的 Boost Serialization 库可以将对象转换为字节以便保存和加载以恢复它们。 不同的格式生成字节序列。
Boost 支持所有这些格式。 序列化仅适用于该库。
在 C++ 中,要序列化的每个对象都需要实现序列化方法。 它应该以档案作为参数; 档案类似于输入/输出数据流。
您可以使用通用运算符并处理机器人保存和加载操作,而不是使用运算符 << 或 >>。 您可以在此网站上阅读有关 boost 序列化的信息。
Apache Avro
Apache Avro 是一个数据序列化系统。 Avro C++ 是一个实现 Avro 规范的 C++ 库,该库旨在用于流管道。
例如,Apache Kafka 使用集中管理的模式执行数据序列化和反序列化。
Avro 不需要代码生成; 您可以使用代码生成工具。 代码生成器读取模式并输出一个 C++ 对象来表示 .schema 中模式的数据。
它还创建代码来序列化该对象并反序列化它。 在这里,所有繁重的编码工作都已为您完成。
即使您希望使用核心 C++ 库编写自定义序列化器或解析器,生成的代码也可以作为如何使用这些库的示例。
这种风格可以工作,但您可以使结构或类可序列化以获得完美的解决方案。
Cap’n Proto
Cap’n Proto 可以轻松地互换数据格式,因为其功能依赖于 RPC(远程过程调用)系统。 Cap'n Proto 中没有编码/解码的概念。
数据交换格式充当编码并代表内存。 您可以通过构建数据轻松地直接从磁盘写入字节。
您可以在 Cap’n Proto 页面上找到最好的示例。
Thrift
Apache Thrift 是一个专注于语言问题的序列化框架。 您可以在 IDL(接口定义语言)中定义抽象数据类型,这将进一步编译为任何支持的语言的源代码。
然后,这些生成的代码将为用户定义类型提供完整的序列化。 Apache Thrift 确保任何数据类型都可以用它读取或写入。
您可以在此页面上找到 Apache Thrift 的最佳示例。
YAS
YAS 是作为 Boost.serialization 的替代品而创建的,因为它的序列化速度较低; 它也是一个仅包含头文件的文件,不需要任何第三方库。 它支持二进制、测试和 JSON 格式,并且需要 C++11。
所有序列化库之间的比较
所有这些库都提供序列化,并且在不同时期都有它们的序列化。 我们只是向您展示这些库的结果,而您可以在此页面上找到代码和更多详细信息(同一行已在上一行中共享)。
在本文中,我们展示了从一篇文章中获取的结果。
该代码已在运行 Ubuntu 16.04 的具有 Intel Core i7 处理器的典型台式计算机上运行,并计算了它们的平均时间。
序列化器 | 对象的大小 | 平均总时间 |
---|---|---|
thrift-binary | 17017 | 1190.22 |
thrift-compact | 13378 | 3474.32 |
protobuf | 16116 | 2312.78 |
boost | 17470 | 1195.04 |
msgpack | 13402 | 2560.6 |
cereal | 17416 | 1052.46 |
avro | 16384 | 4488.18 |
yas | 17416 | 302.7 |
yas-compact | 13321 | 2063.34 |
Cap’n Proto 和 Flatbuffers 以序列化形式存储数据,其中序列化意味着获取指向内部存储的指针。 因此,在 Cap’n Proto 中,我们测量整个构建/序列化/反序列化周期。
对于其他库,我们还可以对已构建的数据结构进行循环序列化/反序列化。
序列化器 | 对象的平均大小 | 总时间 |
---|---|---|
CAPnproto | 17768 | 400.98 |
flatbuffers | 17632 | 491.5 |
如果你根据大小看到上面的数据表示,YAS 比其他库占用更多的对象大小。 尽管如此,如果考虑序列化时间,YAS 花费的时间仍然很短。
因此,YAS 显示了所有库中最快的序列化。
我们希望您现在了解序列化及其用途。 现在,您知道哪些库可以在 C++ 中进行序列化,或者哪个库可以实现最快。
相关文章
C++ 中的 time(NULL) 函数
发布时间:2023/08/24 浏览次数:162 分类:C++
-
本文将讨论 C++ 中的 time(NULL) 函数。C++ 中的 time(NULL) 函数 time() 函数,参数为 NULL,time(NULL),
C++类函数声明中的const关键字
发布时间:2023/08/24 浏览次数:136 分类:C++
-
在C++中,const关键字定义了那些在程序执行期间不会改变并保持不变的值。 对于变量及其保存的数据来说,这听起来非常简单。
C++ 中的 shellExecute() 函数
发布时间:2023/08/24 浏览次数:60 分类:C++
-
这个小型编程教程将讨论 C++ 中的 ShellExecute() 库函数。 该库函数主要用于通过C++程序打开或执行任何文件(例如脚本文件)。C++ 中的 ShellExecute() 函数
C++ 中默认参数的重新定义
发布时间:2023/08/24 浏览次数:170 分类:C++
-
在本文中,您将学习如何处理 C++ 中默认参数错误的重新定义。 C++ 中的默认参数必须在方法或函数的声明或定义中指定,但不能同时指定,因为存在重复。
C++ 形式参数的重新定义
发布时间:2023/08/24 浏览次数:133 分类:C++
-
在本文中,我们将讨论 C++ 中形式参数的重新定义问题。首先,我们将讨论函数定义和形式参数。 接下来,我们将讨论形式参数的重新定义问题。
用 C++ 读取 PPM 文件
发布时间:2023/08/24 浏览次数:108 分类:C++
-
在本文中,我们将了解 PPM 文件并使用 C++ 读取它们。我们将首先讨论并了解 PPM 文件格式。 稍后,我们将学习用 C++ 读取 PPM 文件的分步过程。