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
clearErase all elements.
contains(key)判断Key是否存在
count(key)返回Key的数量
emplaceConstruct 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大小
swapSwap 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解析库

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

buildAdmin的使用笔记

安装buildAdmin 下载完整包&#xff0c;解压进入 buildadmin 的文件夹&#xff0c; 输入命令 composer install 启动的时候使用&#xff0c; php think run 就可以了 为什么启动只需要&#xff0c; php think run 这种启动方式&#xff0c; 我是头一回看见 &#xff0c;后来才…

angular抛出 ExpressionChangedAfterItHasBeenCheckedError错误分析

当变更检测完成后又更改了表达式值时&#xff0c;Angular 就会抛出 ExpressionChangedAfterItHasBeenCheckedError 错误。Angular 只会在开发模式下抛出此错误。 在开发模式下&#xff0c;Angular 在每次变更检测运行后都会执行一次附加检查&#xff0c;以确保绑定没有更改。这…

Mediasoup在node.js下多线程实现

mediasoup基于socket.io的交互消息来完成join-room的请求过程。Join的过程&#xff0c;实际就是获取stream的过程&#xff0c;也就是视频加载时间(video-load-speed)。在RTMP系统&#xff0c;视频加载时间是秒开。Mediasoup给出的第一个frame是I-frame&#xff0c;但由于交互的…

C++编辑修改PDF

PDFWriter是一个易于使用的C创建、修改PDF文档的库 1.创建一个PDF文件 #include #include “PDFWriter.h” int main() { std::cout << “Hello World!\n”; PDFWriter pdfWriter; int retpdfWriter.StartPDF(“D:\mytestwriterpdf.pdf”, ePDFVersion13); if (ret eS…

认识ESP32(什么是RSP32)

一、认识ESP32 ESP32 是一款由乐鑫信息科技&#xff08;Espressif Systems&#xff09;开发的微控制器&#xff08;Microcontroller&#xff09;&#xff0c;它广泛用于物联网&#xff08;IoT&#xff09;和嵌入式系统应用。以下是一些 ESP32 的主要特点&#xff1a; 双核处理…

26 Linux高级篇-Linux面试题

26 Linux高级篇-Linux面试题 文章目录 26 Linux高级篇-Linux面试题1.分析日志t.txt(访问量)&#xff0c;将各个ip地址截取&#xff0c;并统计出现次数&#xff0c;并按从大到小排序(腾讯)2.统计连接到服务器的各个ip情况&#xff0c;并按连接数从大到小排序(腾讯)3.如忘记了mys…

Linux枚举文件目录、获取文件属性

目录 1.枚举指定路径下的文件目录2.获取文件属性stat其他方式&#xff1a;Linux获取文件属性stat()、fstat()、lstat()函数实现stat属性代码 1.枚举指定路径下的文件目录 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <dirent.…

C++11——右值引用和移动语义

✅<1>主页&#xff1a;&#xff1a;我的代码爱吃辣 &#x1f4c3;<2>知识讲解&#xff1a;C11——右值引用 ☂️<3>开发环境&#xff1a;Visual Studio 2022 &#x1f4ac;<4>前言&#xff1a;右值引用&#xff0c;是C11更新的一个非常有价值的语法&am…

[ES]mac安装es、kibana、ik分词器

一、安装es和kibana 1、创建一个网络&#xff0c;网络内的框架(eskibana)互联 docker network create es-net 2、下载es和kibana docker pull elasticsearch:7.12.1 docker pull kibana:7.12.1 3、运行docker命令部署单点eskibana&#xff08;用来操作es&#xff09; doc…

七、高并发内存池--Page Cache

七、高并发内存池–Page Cache 7.1 PageCache的工作原理 PageCache是以span的大小(以页为单位)和下标一一对应为映射关系的哈希桶&#xff0c;下标是几就说明这个哈希桶下挂的span的大小就是几页的&#xff0c;是绝对映射的关系。因为PageCache也是全局只有唯一一个的&#x…

Unity MonoBehaviour事件函数的生命周期

Unity运行时候的默认的几个函数的执行顺序&#xff1a; 首先是Awake&#xff0c;OnEnable&#xff0c;Start等&#xff0c;后面是FixUpdate Update 最后是OnDisable、OnDestroy

VUE之jspreadsheet电子excel表格实时动态高度设置

问题&#xff1a;excel电子表格在不同屏幕大小下横向滚动条会被遮挡 排查原因&#xff1a;由于excel高度固定导致 解决方法&#xff1a;设计页面较多&#xff0c;所以封装公共方法 步骤&#xff1a; 1.使用混入封装动态设置excel高度方法&#xff1a; const mixinJexcel …

WPF实战项目十四(API篇):登录注册接口

1、新建UserDto.cs public class UserDto : BaseDto{private string userName;/// <summary>/// 用户名/// </summary>public string UserName{get { return userName; }set { userName value;OnPropertyChanged(); }}private string account;/// <summary>…

基于侏儒猫鼬算法优化的BP神经网络(预测应用) - 附代码

基于侏儒猫鼬算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码 文章目录 基于侏儒猫鼬算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码1.数据介绍2.侏儒猫鼬优化BP神经网络2.1 BP神经网络参数设置2.2 侏儒猫鼬算法应用 4.测试结果&#xff1a;5…

如何让qt tableView每个item中个别字用不同颜色显示?

如何让qt tableView每个item中个别字用不同颜色显示&#xff1f; 从上面图片可以看到&#xff0c;Item为红色&#xff0c;数字5为黑色。 要实现在一个控件实现不同颜色&#xff0c;目前想到的只有QTextEdit 、QLabel。有两种方法&#xff0c;第一种是代理&#xff0c;第二种是…

李宏毅 2022机器学习 HW2 strong baseline 上分路线

strong baseline上分路线 baseline增加concat_nframes &#xff08;提升明显&#xff09;增加batchnormalization 和 dropout增加hidden layer宽度至512 &#xff08;提升明显&#xff09; 提交文件命名规则为 prediction_{concat_nframes}[{n_hidden_layers}{dropout}_bn].c…

vue自定义键盘

<template><div class"mark" click"isOver"></div><div class"mycar"><div class"mycar_list"><div class"mycar_list_con"><p class"mycar_list_p">车牌号</p>…

Flutter实现StackView

1.让界面之间可以嵌套且执行动画。 2.界面的添加遵循先进后出原则。 3.需要使用AnimateView&#xff0c;请看我上一篇博客。 演示&#xff1a; 代码&#xff1a; Stack: import package:flutter/cupertino.dart;///栈&#xff0c;先进后出 class KqWidgetStack {final Lis…

敏捷开发要点

敏捷开发是一种以人为核心&#xff0c;迭代、增量式的软件开发方法。它强调团队成员的自我管理、面对变化时的快速适应能力&#xff0c;以及持续的沟通和协作。 以下是敏捷开发的几个要点&#xff1a; 敏捷宣言&#xff1a;敏捷开发遵循敏捷宣言&#xff0c;其中包括四个价值声…

Power BI 连接 MySQL 数据库

Power Query 或 Power BI 只提供了对 SQL Server 的直接连接&#xff0c;而不支持其它数据库的直连。所以第一次连接 MySQL 数据库时&#xff0c;就出现下面的错误信。 这就需要我们自己去安装一个连接器组件。https://downloads.mysql.com/archives/c-net/ 错误解决方案 我一…