c++ boost::json
Boost社区12月11日发布了1.75版本,在之前,Boost使用Boost.PropertyTree解析JSON,XML,INI和INFO格式的文件。但是由于成文较早及需要兼容其他的数据格式,相比较于其他的C++解析库,使用时不方便。
Boost.JSON相对于Boost.PropertyTree来所,其只能支持JSON格式的解析,但是其使用方法更为简便,直接。
有两种方法使用Boost.JSON,一种是动态链接库,此时引入头文件boost/json.hpp,同时链接对应的动态库;第二种是使用header only模式,此时只需要引入头文件boost/json/src.hpp即可。
数据类型
array
数组类型,用于储存JSON中的数组。实际使用的时候类似于std::vectorboost::json::value,差异极小。
object
object是JSON键值对的容器,对象类型,用于储存JSON中的对象。实际使用时类似于std::map<std::string, boost::json::value>,但是相对来说,它们之间的差异较大。定义在<boost/json/object.hpp>
项目 | Value |
---|---|
at(key) | 获取指定Key对应的元素的引用(不存在时会抛出out_of_range异常) |
begin/end | 获取iterator |
capacity | 容量 |
cbegin/cend | 获取const iterator |
clear | Erase all elements. |
contains(key) | 判断Key是否存在 |
count(key) | 返回Key的数量 |
emplace | Construct an element in-place. |
empty | 是否为空 |
erase(it/key) | 根据key或iterator移除元素 |
find(key) | 返回指定key的iterator或end()。 |
if_contains(key) | 返回key对应value的指针,或null(不存在时)。 |
insert | 插入元素 |
insert_or_assign | 插入或赋值(若key已存在) |
operator= | Copy assignment.Move assignment.Assignment. |
operator[] | 存在返回对应引用,若不存在则插入null value,并返回 |
reserve | 增加容量(若指定值小于现有容量,则什么也不做) |
size | 大小 |
swap | Swap two objects. |
max_size | 静态成员,返回object能保存元素的最大数量。 |
string
字符串类型,用于储存JSON中的字符串。实际使用时和std::basic_string类似,不过其只支持UTF-8编码,如果需要支持其他编码,在解码时候需要修改option中相应的选项。
value
表示JSON值的类型,可以储存任意类型,也可以变换为各种类型。其中有一些特色的函数比如as_object,get_array,emplace_int64之类的。它们的工作都类似,将boost::json::value对象转化为对应的类型。但是他们之间也有一定的区别。
构造json
{"a_string" : "test_string","a_number" : 123,"a_null" : null,"a_array" : [1, "2", {"123" : "123"}],"a_object" : {"a_name": "a_data"},"a_bool" : true
}
构造的方法也很简单:定义一个object,然后设定各个value即可
boost::json::object val;
val["a_string"] = "test_string";
val["a_number"] = 123;
val["a_null"] = nullptr;
val["a_array"] = {1, "2", boost::json::object({{"123", "123"}})
};
val["a_object"].emplace_object()["a_name"] = "a_data";
val["a_bool"] = true;
Boost.JSON支持使用std::initializer_list来构造自己的对象。所以也可以这样使用:
boost::json::value val2 = {{"a_string", "test_string"},{"a_number", 123},{"a_null", nullptr},{"a_array", {1, "2", {{"123", "123"}}}},{"a_object", {{"a_name", "a_data"}}},{"a_bool", true}
};
但是使用initializer_list构造时,有时很难区分是数组还是对象,可以明确指定
// 构造[["data", "value"]]
boost::json::value jsonAry = {boost::json::array({"data", "value"})};// 构造{"data": "value"}
boost::json::value jsonObj = boost::json::object({{"data", "value"}});
序列化
生成了json对象以后,就可以使用serialize对对象进行序列化了。
std::cout << boost::json::serialize(val2) << std::endl;
除了直接把整个对象直接输出,Boost.JSON还支持分部分进行流输出,这种方法在数据量较大时,可以有效降低内存占用。
boost::json::serializer ser;
ser.reset(&val);char temp_buff[6];
while (!ser.done()) {std::memset(temp_buff, 0, sizeof(char) * 6);ser.read(temp_buff, 5);std::cout << temp_buff << std::endl;
}
如果缓存变量是数组,还可以直接使用ser.read(temp_buff)。
需要注意的是,ser.read并不会默认在字符串末尾加\0,所以如果需要直接输出,在输入时对缓存置0,同时为\0空余一个字符。
也可以直接使用输出的boost::string_view。
对象序列化
对象转换为JSON,Boost.JSON提供了一个非常简单的方法:只需要在需要序列化的类的命名空间中,定义一个重载函数tag_invoke(是类所在的命名空间,而不是在类里面定义),然后通过value_from即可方便地序列化对象了:
namespace NSJsonTest {class MyClass {public:int a;int b;MyClass (int a = 0, int b = 1):a(a), b(b) {}};void tag_invoke(boost::json::value_from_tag, boost::json::value &jv, MyClass const &c) {auto & jo = jv.emplace_object();jo["a"] = c.a;jo["b"] = c.b;}MyClass myObj;auto jv = boost::json::value_from(myObj)
}
其中,boost::json::value_from_tag是作为标签存在的,方便Boost.JSON分辨序列化函数的。jv是输出的JSON对象,c是输入的对象。
boost::json::value_from(MyObj)
使用的话,直接调用value_from函数即可。
序列化还有一个好处就是,可以在使用std::initializer_list初始化JSON对象时,直接使用自定义对象。譬如:
boost::json::value val = {MyObj};
这里的val是一个数组,里面包含了一个对象MyObj。
反序列化
使用boost::json::parse
auto decode_val = boost::json::parse("{\"123\": [1, 2, 3]}");
增加错误处理
boost::json::error_code ec;
boost::json::parse("{\"123\": [1, 2, 3]}", ec);
std::cout << ec.message() << std::endl;boost::json::parse("{\"123\": [1, 2, 3}", ec);
std::cout << ec.message() << std::endl;
对象反序列化
与对象序列化对应的是对象反序列化;也是在命名空间中定义个tag_invoke函数,然后即可通过value_to把JSON对象反序列化为类对象了:
MyClass tag_invoke(boost::json::value_to_tag<MyClass>, boost::json::value const &jv) {auto &jo = jv.as_object();return MyClass(jo.at("a").as_int64(), jo.at("b").as_int64());
}// jv为前面序列化时的对象
auto myObj = boost::json::value_to<MyClass>(jv);
需要注意的是,由于传入的jv是被const修饰的,所以不能类似于jv[“a”]使用。
使用也和上面的类似,提供了一个value_to<>模板函数。
auto MyObj = boost::json::value_to<MyNameSpace::MyClass>(vj);
无论是序列化还是反序列化,对于标准库中的容器,Boost.JSON都可以直接使用。
流输入
通过stream_parser可以流的方式读入要解析的字符串
boost::json::stream_parser p;
p.reset();p.write("[1, 2,");
p.write("3]");
p.finish();std::cout << boost::json::serialize(p.release()) << std::endl;
示例
json文件:
#include <boost/json.hpp>
#include <boost/json/src.hpp>
#include <iostream>
#include <iterator>
#include <fstream>
namespace json = boost::json;struct Rec {int64_t number;std::string string;friend Rec tag_invoke(json::value_to_tag<Rec>, json::value const& v) {auto& o = v.as_object();return {o.at("number").as_int64(),boost::json::value_to<std::string>(o.at("string")),};}friend void tag_invoke(json::value_from_tag, json::value& v, Rec const& rec){v = json::object{{"number", rec.number},{"string", rec.string},};}
};int main() {std::ifstream ifs("../input.json");std::string input(std::istreambuf_iterator<char>(ifs), {});using Recs = std::vector<Rec>;Recs recs = boost::json::value_to<std::vector<Rec>>(json::parse(input));for (auto& [n, s] : recs) {std::cout << "Rec { " << n << ", " << std::quoted(s) << " }\n";// some frivolous changes:n *= 2;reverse(begin(s), end(s));}std::cout << "Modified json: " << json::value_from(recs) << "\n";
}
参考
Boost.JSON Boost的JSON解析库
相关文章:

c++ boost::json
Boost社区12月11日发布了1.75版本,在之前,Boost使用Boost.PropertyTree解析JSON,XML,INI和INFO格式的文件。但是由于成文较早及需要兼容其他的数据格式,相比较于其他的…...

《Flink学习笔记》——第九章 多流转换
无论是基本的简单转换和聚合,还是基于窗口的计算,我们都是针对一条流上的数据进行处理的。而在实际应用中,可能需要将不同来源的数据连接合并在一起处理,也有可能需要将一条流拆分开,所以经常会有对多条流进行处理的场…...

openmmlab出现KeyError: ‘xxx is not in the model registry....‘
问题描述 在复现基于mmpose框架的算法时,运行程序出现KeyError: xxx is not in the model registry....的问题,报错原因是自定义的backbone等结构或者某些当前代码使用的方法没有注册到现有的包中, 导致在import的时候无法导入该方法。 解决方案 找到…...

错误代码0x80131500要怎么解决?快速修复方法
错误代码0x80131500通常与.NET Framework 相关的问题有关。它可能表示.NET Framework的安装损坏、版本冲突或系统文件缺失等。下面我们一起来探讨一下解决错误代码0x80131500有哪些。 以下是一些解决方法 安装最新的.NET Framework版本:访问Microsoft官方网站&…...

PMO(Project Management Office)
PMO 是项目管理办公室(Project Management Office)的缩写。它是组织内的一个部门或团队,负责支持和促进项目管理活动,以确保项目按时、按预算、按要求完成。 PMO 的职责和角色可以因组织的性质和需求而有所不同,但通常…...

STM32 CUBEMX CAN通信数据发送失败原因分析
CAN通信是一种数据通信协议,用于在不同设备之间进行通信。它是一种高效的、实时的、可靠的、多主机的、串行通信系统,通常用于汽车电子、工业自动化等领域。CAN通信协议是由德国BOSCH公司于1986年引入,并在欧洲和日本广泛使用。CAN通信具有独…...

长安链并行调度机制(2):DAG构建和从节点执行流程
长安链采用高效的并行调度方式执行交易,了解长安链交易调度、冲突检测和DAG构建流程有助于开发者更好地理解长安链并行调度的运行机制,帮助开发者编写高质量、低冲突的智能合约,更好地构建区块链应用。 上一篇内容我们说明了长安链交易调度、…...

leetcode做题笔记110. 平衡二叉树
给定一个二叉树,判断它是否是高度平衡的二叉树。 本题中,一棵高度平衡二叉树定义为: 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。 思路一:递归 int height(struct TreeNode* root) {if (root NULL) {return…...

iOS开发Swift-字符串与字符
1.字符串的定义 let someString "some string value"2.多行字符串的定义(""") let quotation """ 有一个人前来买瓜。 "这瓜甜吗?"他问。 """前一个"""前和后一个""&…...

Linux Kernel:syscall之fork与exec
环境: Kernel Version:Linux-5.10 ARCH:ARM64 一:前言 上一节我们提到了进程的产生方式fork,exec与clone,本节将详细分析fork和exec族系统调用的具体实现。通常这些调用不是由应用程序直接发出的,而是通过一个中间层调用,即负责与内核通信的C标准库。从用户状态切换到…...

CentOS 修改MySQL密码
CentOS 修改MySQL密码 1.登录MySQL 2.执行如下命令 update user set passwordpassword(mivbAs7Awc) where userroot;报错如下: Unknown column ‘password’ in ‘field list’ 3.执行如下命令 update user set passwordpassword(mivbAs7Awc) where userroot碰到…...

Android通过setaffinity实现绑核
有时候为了降低App算力占用,会把关键的线程绑定到大核中,下面介绍一种绑核的方式 查看绑核 查看pid :/ # ps -A | grep test u0_a15 25178 405 15950272 176544 do_epoll_wait 0 S com.test.jnites查看线程号 top -H -p 25178 25224 u0_…...

stm32的位带操作
在51单片机中,我们可以使用P2^1来对单片机的某一位进行操作,到了stm32,我们通过位带操作,将寄存器的每一位映射到一个32位的地址。如下是我查资料摘录的一些图片。 映射方式 SRAM: AliasAddr 0x22000000 (A-0X20000000)*8*4n*4…...

Java 电子招标采购系统源码:营造全面规范安全的电子招投标环境,促进招投标市场健康可持续发展
营造全面规范安全的电子招投标环境,促进招投标市场健康可持续发展 传统采购模式面临的挑战 一、立项管理 1、招标立项申请 功能点:招标类项目立项申请入口,用户可以保存为草稿,提交。 2、非招标立项申请 功能点:非招标…...

https协议经过SpringMVC重定向之后变成http协议
之前项目的协议还是http,当改为https之后,就出现了这个问题。 服务访问地址:https://wuxinke.demo.com 访问某个页面的地址:https://wuxinke.demo.com/aps/judgeProviderOrCtenant.ht 经SpringMVC重定向之后,地址变…...

iOS 分别对一张图的局部进行磨砂,拼接起来不能贴合
效果图 需求,由于视图层级的原因,需要对图片分开进行磨砂, 然后组合在一起 如图,上下两部分,上下两个UIImageVIew大小相同,都是和图片同样的大小,只是上面的UIimageVIew 只展示上半部份 &#…...

与面试官互动:建立积极的技术讨论氛围
🌷🍁 博主猫头虎 带您 Go to New World.✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 &a…...

计算机竞赛 基于YOLO实现的口罩佩戴检测 - python opemcv 深度学习
文章目录 0 前言1 课题介绍2 算法原理2.1 算法简介2.2 网络架构 3 关键代码4 数据集4.1 安装4.2 打开4.3 选择yolo标注格式4.4 打标签4.5 保存 5 训练6 实现效果6.1 pyqt实现简单GUI6.3 视频识别效果6.4 摄像头实时识别 7 最后 0 前言 🔥 优质竞赛项目系列…...

完美解决Ubuntu网络故障,连接异常,IP地址一直显示127.0.0.1
终端输入ifconfig显示虚拟机IP地址为127.0.0.1,具体输出内容如下: wxyubuntu:~$ ifconfig lo: flags73<UP,LOOPBACK,RUNNING> mtu 65536inet 127.0.0.1 netmask 255.0.0.0inet6 ::1 prefixlen 128 scopeid 0x10<host>loop txqueuelen …...

手机无人直播软件有哪些,又有哪些优势?
如今,随着智能手机的普及和移动互联网的发展,手机无人直播成为了一个炙手可热的领域。手机无人直播软件为用户提供了便捷、灵活的直播方式,让更多商家人能够实现自己的直播带货的梦想。接下来,我们将探讨手机无人直播软件有哪些&a…...

解密算法与数据结构面试:程序员如何应对挑战
🌷🍁 博主猫头虎 带您 Go to New World.✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 &a…...

分布式事务7种(秒懂-2PC、3PC、TCC、Saga、本地事务表、MQ事务消息、最大努力通)
参考文章: 七种常见分布式事务详解(2PC、3PC、TCC、Saga、本地事务表、MQ事务消息、最大努力通知)_张维鹏的博客-CSDN博客 分布式事务 (秒懂)_40岁资深老架构师尼恩的博客-CSDN博客 分布式事务:在分布式…...

基于Java+SpringBoot+Vue前后端分离美食推荐商城设计和实现
博主介绍:✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专…...

最新ChatGPT程序源码+AI系统+详细图文搭建教程/支持GPT4/AI绘画/H5端/完整Prompt知识库
一、AI系统 如何搭建部署人工智能源码、AI创作系统、ChatGPT系统呢?小编这里写一个详细图文教程吧!SparkAi使用Nestjs和Vue3框架技术,持续集成AI能力到AIGC系统! 1.1 程序核心功能 程序已支持ChatGPT3.5/GPT-4提问、AI绘画、Mi…...

本地启动若依微服务版本
前置工作: 1.导入sql文件 2.安装完nacos 3.安装完redis 启动步骤: 1.开启nacos,在bin目录下 startup.cmd -m standalone 注意:在这之前要配置nacos持久化,修改conf/application.properties文件,增加支持…...

HTML的span标签的作用是什么?答:对文本内容进行精细的样式化和标记。
当谈到HTML中的<span>标签时,它是一个非常基本且灵活的内联元素。它通常用于在文本中应用样式、添加额外的语义或将特定部分标记为一个单独的区域。<span>标签本身并不会给其中的内容带来任何视觉上的变化,但它可以与CSS一起使用,…...

基于微服务、Java、Springcloud、Vue、MySQL开发的智慧工地管理系统源码
智慧工地聚焦施工现场岗位一线,围绕“人、机、料、法、环”五大要素,数字化工地平台与现场多个子系统的互联实现了工地业务间的互联互通和协同共享。数字化工地管理平台能够盘活工地各大项目之间孤立的信息系统,实现数据的统一接入、处理与维…...

Redis内存策略
文章目录 Redis内存策略过期策略DB结构惰性删除周期删除 淘汰策略 Redis内存策略 Redis是基于内存存储,所以其性能很强。但单节点的Redis内存不宜过大,否则会影响持久化或主从同步性能。 可以手动修改配置文件来设置Redis的最大内存 # 格式࿱…...

视频监控/视频汇聚/视频云存储EasyCVR平台HLS流集成在小程序无法播放问题排查
安防视频/视频云存储/视频集中存储EasyCVR视频监控综合管理平台可以根据不同的场景需求,让平台在内网、专网、VPN、广域网、互联网等各种环境下进行音视频的采集、接入与多端分发。在视频能力上,视频云存储平台EasyCVR可实现视频实时直播、云端录像、视频…...

vue3将通用组件注册成全局组件
一、问题重现 我们用过vue的人都知道会有一个components文件夹用来存放我们的通用组件: 这里我的通用组件就有四个,但是有一些是使用评率比较高的,如果很多地方要使用我还得导入相同的组件,写的都是一样的代码: impo…...