C++序列化Cereal库的使用

目录

  • 一、什么是序列化
  • 二、Cereal序列化库
  • 三、下载与编译
  • 四、使用

一、什么是序列化

序列化在编程中有以下几个重要的原因:

  1. 数据存储:将数据对象序列化为一种持久化的格式,可以将其存储在文件、数据库或其他存储介质中。这样可以在程序的不同运行之间保存数据的状态,以便后续使用。

  2. 网络传输:当需要在网络上发送数据时,将数据序列化为一种适合传输的格式(如二进制或文本)可以确保数据能够正确地在网络中传输,并在接收端进行反序列化还原为原始的数据对象。

  3. 数据交换:在不同的系统或应用程序之间进行数据交换时,序列化可以提供一种通用的格式,使得数据能够在不同的环境中被理解和处理。

  4. 对象状态保存:序列化可以用于保存对象的当前状态,以便在需要时恢复到该状态。这在一些需要记录和恢复对象状态的场景中非常有用,例如游戏中的保存和加载功能。

  5. 分布式系统:在分布式系统中,序列化可以用于在不同的节点之间传递数据对象,确保数据的一致性和可靠性。

  6. 缓存和持久化:将数据序列化后,可以将其存储在缓存中以提高访问速度,或者将其持久化到磁盘以长期保存。

  7. 跨语言支持:一些序列化格式是跨语言的,这意味着可以在不同的编程语言中进行序列化和反序列化操作,促进了不同语言之间的互操作性。

    通过序列化,我们可以将复杂的数据结构转换为一种可存储、可传输和可恢复的形式,方便数据的管理和处理。不同的序列化库和技术在性能、灵活性和兼容性方面可能有所不同,选择适合具体需求的序列化方法可以提高开发效率和系统的可维护性。

    一般使用的序列化有json、protobuf,但是这些方式局限性很大,只支持基本数据类型和数组,对于智能指针、map这些复杂数据类型不支持,使用起来极为不便。

二、Cereal序列化库

Cereal 是一个 C++11 的序列化库,它是现代、轻量级、快速和灵活的,可以用来保存和加载几乎所有类型的数据。

Cereal 支持将自定义数据类型序列化成 JSON、XML、二进制,反之也可以实现反序列化。

三、下载与编译

Cereal GitHub 地址:https://github.com/USCiLab/cereal。

Cereal 是一个 head only 的库,无需编译。

四、使用

Cereal可以大体分为三类,结构体序列化反序列化、数据与JSON序列化反序列化、数据与XML序列化反序列化。

结构体序列化反序列化

#include <iomanip>
#include <iostream>
#include <sstream>
#include <vector>
#include <unordered_map>
#include <queue>
#include <fstream>#include "cereal/archives/json.hpp"
#include "cereal/archives/binary.hpp"// 序列化哪种类型就包含哪种类型的hpp
#include "cereal/types/string.hpp"
#include "cereal/types/vector.hpp"
#include "cereal/types/unordered_map.hpp"
#include "cereal/types/queue.hpp"
#include "cereal/types/memory.hpp"// 自定义结构体
struct A
{int n;template<class Archive>void serialize(Archive& archive) // 序列化函数,函数名必须为serialize{archive(n);}
};struct demo_struct 
{ int id{};std::string name;std::vector<double> values;std::unordered_map<int, int> mp;std::queue<int> qu;std::shared_ptr<int>  num;A a;template<class Archive>void serialize(Archive& archive) // 序列化函数{archive(id, name, values,mp,qu,num,a);}
};// 序列化结构体
void SerializeStruc()
{demo_struct data; // 自定义对象data.id = 1;data.name = "Example";data.values = { 3.14, 2.718, 1.414 };data.num = std::make_shared<int>(2);data.mp[1] = 1;data.mp[2] = 2;data.qu.push(1);data.qu.push(2);data.a.n = 3;// 将结构体序列化为Binary字符串std::ostringstream oss(std::ios::binary);{cereal::BinaryOutputArchive   archive(oss);archive(data);}// 输出序列化后的Binary字符串到控制台std::string serializedData = oss.str();for (char byte : serializedData) {std::cout << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(static_cast<unsigned char>(byte)) << " ";}std::cout << std::endl;// 从Binary字符串反序列化结构体{demo_struct loaded_data;std::istringstream iss(oss.str());cereal::BinaryInputArchive  archive(iss);archive(loaded_data);// 显示反序列化后的数据std::cout << "\nLoaded ID: " << loaded_data.id << std::endl;std::cout << "Loaded Name: " << loaded_data.name << std::endl;std::cout << "Loaded Num: " << *loaded_data.num << std::endl;std::cout << "Loaded Values: ";for (const auto& value : loaded_data.values) {std::cout << value << " ";}std::cout << std::endl;std::cout << "Loaded mp: ";for (const auto& it : loaded_data.mp)std::cout << it.first << "=" << it.second << " ";std::cout << std::endl;std::cout << "Loaded qu: ";while (!loaded_data.qu.empty()){std::cout << loaded_data.qu.front() << " ";loaded_data.qu.pop();}std::cout << std::endl;std::cout << "Loaded a: " << loaded_data.a.n << std::endl;}
}int main() {SerializeStruc();system("pause");return 0;
}

在这里插入图片描述

数据与JSON序列化反序列化

1、将基本数据类型保存为JSON文件

	// 写入JSON文件std::ofstream file("out.json");cereal::JSONOutputArchive archive(file);std::string s[] = { "this is a string", " 中文string也是可以支持的" };std::vector<double> vec = { 1.00001, 2e3, 30.1, -4, 5 };// 相当于将vec和s作为JSON的KEY值,见如下JSON文件archive(CEREAL_NVP(vec), CEREAL_NVP(s));// 文件关闭后写入的json文件少一个大括号,不知道为什么// file.close(); 

在这里插入图片描述

2、读取JSON文件数据

std::ifstream readFile("out.json");cereal::JSONInputArchive readArchive(readFile);// 注意变量名和写入时需要一致std::vector<double> vec;std::string s[2];// 相当于按照KEY值去读readArchive(CEREAL_NVP(vec),CEREAL_NVP(s));for (const auto& it : vec)std::cout << it << " ";std::cout << s[0] << " " << s[1] << std::endl;readFile.close();

在这里插入图片描述

3、自定义结构体与JSON的序列化反序列化

#include <iomanip>
#include <iostream>
#include <sstream>
#include <vector>
#include <unordered_map>
#include <queue>
#include <fstream>#include "cereal/archives/json.hpp"
#include "cereal/archives/binary.hpp"// 序列化哪种类型就包含哪种类型的hpp
#include "cereal/types/string.hpp"
#include "cereal/types/vector.hpp"
#include "cereal/types/unordered_map.hpp"
#include "cereal/types/queue.hpp"
#include "cereal/types/memory.hpp"// 自定义结构体
struct A
{int n;template<class Archive>void serialize(Archive& archive) // 序列化函数,函数名必须为serialize{archive(n);// 不将类型名作为KEY值,采用默认,注意区别//archive(cereal::make_nvp("n", n));}
};struct demo_struct 
{ int id{};std::string name;std::vector<double> values;std::unordered_map<int, int> mp;std::queue<int> qu;std::shared_ptr<int>  num;A a;template<class Archive>void serialize(Archive& archive) // 序列化函数{archive(id, name, values,mp,qu,num,a);// 不将类型名作为KEY值,采用默认,注意区别//archive(cereal::make_nvp("id", id), cereal::make_nvp("name", name)//  , cereal::make_nvp("values", values), cereal::make_nvp("mp", mp)//  , cereal::make_nvp("qu", qu), cereal::make_nvp("num", num)//  , cereal::make_nvp("A", a));}
};// 序列化json
void SerializeJson()
{demo_struct data; // 自定义对象data.id = 1;data.name = "Example";data.values = { 3.14, 2.718, 1.414 };data.num = std::make_shared<int>(2);data.mp[1] = 1;data.mp[2] = 2;data.qu.push(1);data.qu.push(2);data.a.n = 3;// 将结构体序列化为JSON字符串std::ostringstream oss;{cereal::JSONOutputArchive  archive(oss);archive(cereal::make_nvp("demo_struct", data));}// 输出序列化后的JSON字符串到控制台std::cout << "序列化为 JSON:\n" << oss.str() << std::endl;// 从JSON字符串反序列化结构体{demo_struct loaded_data;std::istringstream iss(oss.str());cereal::JSONInputArchive  archive(iss);archive(cereal::make_nvp("demo_struct", loaded_data));// 显示反序列化后的数据std::cout << "\nLoaded ID: " << loaded_data.id << std::endl;std::cout << "Loaded Name: " << loaded_data.name << std::endl;std::cout << "Loaded Num: " << *loaded_data.num << std::endl;std::cout << "Loaded Values: ";for (const auto& value : loaded_data.values)std::cout << value << " ";std::cout << std::endl;std::cout << "Loaded mp: ";for (const auto& it : loaded_data.mp)std::cout << it.first << "=" << it.second << " ";std::cout << std::endl;std::cout << "Loaded qu: ";while (!loaded_data.qu.empty()){std::cout << loaded_data.qu.front() << " ";loaded_data.qu.pop();}std::cout << std::endl;std::cout << "Loaded a: " << loaded_data.a.n << std::endl;}
}int main() {SerializeJson();system("pause");return 0;
}

在这里插入图片描述

4、XML序列化反序列化

XML用法和JSON用法一致,区别在于

// 序列化
cereal::XMLOutputArchive  // XML序列化
cereal::JSONOutputArchive // JSON序列化// 反序列化
cereal::XMLInputArchive 
cereal::JSONInputArchive
#include <iomanip>
#include <iostream>
#include <sstream>
#include <vector>
#include <unordered_map>
#include <queue>
#include <fstream>#include "cereal/archives/json.hpp"
#include "cereal/archives/xml.hpp"
#include "cereal/archives/binary.hpp"// 序列化哪种类型就包含哪种类型的hpp
#include "cereal/types/string.hpp"
#include "cereal/types/vector.hpp"
#include "cereal/types/unordered_map.hpp"
#include "cereal/types/queue.hpp"
#include "cereal/types/memory.hpp"// 自定义结构体
struct A
{int n;template<class Archive>void serialize(Archive& archive) // 序列化函数,函数名必须为serialize{//archive(n);archive(cereal::make_nvp("n", n));}
};struct demo_struct 
{ int id{};std::string name;std::vector<double> values;std::unordered_map<int, int> mp;std::queue<int> qu;std::shared_ptr<int>  num;A a;template<class Archive>void serialize(Archive& archive) // 序列化函数{//archive(id, name, values,mp,qu,num,a);archive(cereal::make_nvp("id", id), cereal::make_nvp("name", name), cereal::make_nvp("values", values), cereal::make_nvp("mp", mp), cereal::make_nvp("qu", qu), cereal::make_nvp("num", num), cereal::make_nvp("A", a));}
};void SerializeXML()
{demo_struct data; // 自定义对象data.id = 1;data.name = "Example";data.values = { 3.14, 2.718, 1.414 };data.num = std::make_shared<int>(2);data.mp[1] = 1;data.mp[2] = 2;data.qu.push(1);data.qu.push(2);data.a.n = 3;// 将结构体序列化为XML字符串std::ostringstream oss;{cereal::XMLOutputArchive  archive(oss);archive(cereal::make_nvp("demo_struct", data));}// 输出序列化后的XML字符串到控制台std::cout << "序列化为 XML:\n" << oss.str() << std::endl;// 从XML字符串反序列化结构体{demo_struct loaded_data;std::istringstream iss(oss.str());cereal::XMLInputArchive  archive(iss);archive(cereal::make_nvp("demo_struct", loaded_data));// 显示反序列化后的数据std::cout << "\nLoaded ID: " << loaded_data.id << std::endl;std::cout << "Loaded Name: " << loaded_data.name << std::endl;std::cout << "Loaded Num: " << *loaded_data.num << std::endl;std::cout << "Loaded Values: ";for (const auto& value : loaded_data.values)std::cout << value << " ";std::cout << std::endl;std::cout << "Loaded mp: ";for (const auto& it : loaded_data.mp)std::cout << it.first << "=" << it.second << " ";std::cout << std::endl;std::cout << "Loaded qu: ";while (!loaded_data.qu.empty()){std::cout << loaded_data.qu.front() << " ";loaded_data.qu.pop();}std::cout << std::endl;std::cout << "Loaded a: " << loaded_data.a.n << std::endl;}
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3269697.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

视觉SLAM第二讲

SLAM分为定位和建图两个问题。 定位问题 定位问题是通过传感器观测数据直接或间接求解位置和姿态。 通常可以分为两类&#xff1a;基于已知地图的定位和基于未知地图的定位。 基于已知地图的定位 利用预先构建的地图&#xff0c;结合传感器数据进行全局定位。SLAM中的全局…

HDU1056——HangOver,HDU1057——A New Growth Industry,HDU1058——Humble Numbers

目录 HDU1056——HangOver 题目描述 运行代码 代码思路 HDU1057——A New Growth Industry 题目描述 运行代码 代码思路 HDU1058——Humble Numbers 题目描述 运行代码 代码思路 HDU1056——HangOver 题目描述 Problem - 1056 运行代码 #include <iostream&…

html+css+js 实现马赛克背景按钮

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享htmlcss 绚丽效果&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 文…

报错Found dtype Long but expected Float解决办法

Found dtype Long but expected Float错误通常发生在尝试将一个数据类型为Long的张量传递给一个期望数据类型为Float的函数或操作时。 在PyTorch中&#xff0c;Long和Float是两种常见的数据类型&#xff0c;分别对应于64位整数和32位浮点数。某些函数或操作可能只接受特定数据…

详细分析 Bladex中的swagger-resources资源未授权访问的解决方法

目录 1. 问题所示2. 原理分析2.1 RouterFunctionConfiguration 类2.2 SwaggerResourceHandler 类3. 解决方法3.1 网关过滤3.2 去除配置3.3 代码修改4. 彩蛋1. 问题所示 从而也导致资源接口文件泄露 https://xxx/swagger-resources 或者 ip:端口号/swagger-resources 2. 原理分…

数据仓库设计与数据建模初探

一、为什么需要引入数据仓库 数据仓库本质上是一种数据库&#xff0c;但它有一些特定的特性和用途&#xff0c;使其与传统的关系数据库有所不同。 需要分析的数据量较大&#xff08;单批 GiB&#xff09;&#xff0c;此时事务性数据库分析性能堪忧&#xff0c;需要通过建立索…

空调压力传感器

空调压力传感器是自动空调控制系统的一个传感器元件&#xff0c;其作用是防止制冷系统在极限制冷剂管路的压力下工作&#xff0c;并帮助控制发动机冷却风扇的转速。压力传感器安装在发动机舱内空调高压管路上。 该传感器向发动机ECM或空调控制单元输出压力信号&#xff0c;当检…

自学网络安全,从小白到大神的破茧之路!

在当今数字化高速发展的时代&#xff0c;网络安全已经成为了至关重要的领域。无论是个人的隐私保护&#xff0c;还是企业、国家的关键信息资产维护&#xff0c;都离不开网络安全的有力保障。出于对这一领域的浓厚兴趣以及对未来职业发展的清晰规划&#xff0c;我毅然决然地踏上…

【计算机网络】TCP负载均衡实验

一&#xff1a;实验目的 1&#xff1a;了解TCP负载均衡的配置。 2&#xff1a;学会使用NAT技术处理和外部网络的连接。 二&#xff1a;实验仪器设备及软件 硬件&#xff1a;RCMS交换机、网线、内网网卡接口、Windows 2019操作系统的计算机等。具体为&#xff1a;二层交换机1…

Python数据分析案例55——基于LSTM结构自编码器的多变量时间序列异常值监测

案例背景 时间序列的异常值检测是方兴未艾的话题。比如很多单变量的&#xff0c;一条风速&#xff0c;一条用电量这种做时间序列异常值检测&#xff0c;想查看一下哪个时间点的用电量异常。 多变量时间序列由不同变量随时间变化的序列组成&#xff0c;这些时间序列在实际应用…

LivePortrait优化版,表情迁移,数字人,视频驱动视频v2v(WIN,MAC)

大家好&#xff0c;今天给大家分享一个由快手、中国科学技术大学和复旦大学联合团队开发的表情迁移项目——LivePortrait。老规矩&#xff0c;整合包也已经准备OK了。&#xff08;MAC用户不要担心&#xff01;这次有有有有MAC的哦&#xff01;&#xff09; 只需要上传一段参考视…

Godot入门 04平台设计

新建创景&#xff0c;添加AnimatableBody2D节点。 添加Sprite2D节点 拖动图片 剪裁图片&#xff0c;吸附模式&#xff1a;像素吸附 添加CollisionShape2D&#xff0c;设置实际形状为矩形 重命名AnimatableBody2D节点为Platform&#xff0c;保存场景&#xff0c;拖动platform场景…

20 B端产品的数据分析

数据分析的价值 数据衡量业务&#xff1a;通过管理数据报表&#xff0c;可以快速衡量业务发展状态。 数据洞察业务&#xff1a;通过数据分析&#xff0c;可以找到业务发展的机遇。 数据驱动指导业务&#xff1a;基于数据&#xff0c;驱动业务决策&#xff0c;数据支撑决策。 …

Django5之视图装饰器

本节主要介绍Django框架视图层中装饰器的内容。视图装饰器用来对视图函数进行相关的控制操作&#xff0c;实现了对各种HTTP特性的支持功能。 4.5.1 允许HTTP方法 在Django框架中&#xff0c;位于django.views.decorators.http模块的装饰器被用来限制可以访问该视图的HTTP请求…

RICHTEK立锜科技静态耗电的nanoPower Buck转换器RT5713/RT5714

RT5713/14 是静态耗电只有 360nA 的高效同步 Buck 转换器&#xff0c;即使负载电流低达 10mA 时也能保持其很高的转换效率。其输入电压范围为 2.2V~5.5V&#xff0c;输出电压为两档可选&#xff0c;通过电压选择引脚 VSEL 即可进行设定&#xff0c;负载能力可达 0.5A/1A。 它采…

字符串格式化(不造轮子)

jdk提供的字符串格式化工具类String.format、MessageFormat使用的占位符不够直观&#xff0c;除了使用重量级的模板引擎外&#xff0c;寻求一种轻量级的方式 Apache StringSubstitutor commons-text包下的org.apache.commons.text.StringSubstitutor类 <dependency><…

如何知道一个字段在selenium中是否可编辑?

这篇文章将检查我们如何使用Java检查selenium webdriver中的字段是否可编辑。 我们如何知道我们是否可以编辑字段&#xff1f;“readonly”属性控制字段的可编辑性。如果元素上存在“readonly”属性&#xff0c;则无法编辑或操作该元素或字段。 因此&#xff0c;如果我们找到一…

MySQL练手 --- 1789. 员工的直属部门

题目链接&#xff1a;1789. 员工的直属部门 这道题虽然是个简单题&#xff0c;但是"坑"倒是不少&#xff0c;所以记录一下 思路&#xff1a; 题目要干&#xff1a; 一个员工可以属于多个部门。当一个员工加入超过一个部门的时候&#xff0c;他需要决定哪个部门是…

ComfyUI插件:ComfyUI Impact 节点(一)

前言&#xff1a; 学习ComfyUI是一场持久战&#xff0c;而 ComfyUI Impact 是一个庞大的模块节点库&#xff0c;内置许多非常实用且强大的功能节点 &#xff0c;例如检测器、细节强化器、预览桥、通配符、Hook、图片发送器、图片接收器等等。通过这些节点的组合运用&#xff0…

如何保证前后端交互信息不被篡改。

先说说前后端有哪些认证方式来保证&#xff1a; 基于 session 的认证方式&#xff1a;前端在用户登录成功后&#xff0c;后端会在服务器端生成一个唯一的 session ID&#xff0c;并将该 session ID 返回给前端&#xff0c;在后续的请求中&#xff0c;前端需要带上该 session ID…