当前位置: 首页 > news >正文

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.lryc.cn/news/144695.html

相关文章:

  • 《Flink学习笔记》——第九章 多流转换
  • openmmlab出现KeyError: ‘xxx is not in the model registry....‘
  • 错误代码0x80131500要怎么解决?快速修复方法
  • PMO(Project Management Office)
  • STM32 CUBEMX CAN通信数据发送失败原因分析
  • 长安链并行调度机制(2):DAG构建和从节点执行流程
  • leetcode做题笔记110. 平衡二叉树
  • iOS开发Swift-字符串与字符
  • Linux Kernel:syscall之fork与exec
  • CentOS 修改MySQL密码
  • Android通过setaffinity实现绑核
  • stm32的位带操作
  • Java 电子招标采购系统源码:营造全面规范安全的电子招投标环境,促进招投标市场健康可持续发展
  • https协议经过SpringMVC重定向之后变成http协议
  • iOS 分别对一张图的局部进行磨砂,拼接起来不能贴合
  • 与面试官互动:建立积极的技术讨论氛围
  • 计算机竞赛 基于YOLO实现的口罩佩戴检测 - python opemcv 深度学习
  • 完美解决Ubuntu网络故障,连接异常,IP地址一直显示127.0.0.1
  • 手机无人直播软件有哪些,又有哪些优势?
  • 解密算法与数据结构面试:程序员如何应对挑战
  • 分布式事务7种(秒懂-2PC、3PC、TCC、Saga、本地事务表、MQ事务消息、最大努力通)
  • 基于Java+SpringBoot+Vue前后端分离美食推荐商城设计和实现
  • 最新ChatGPT程序源码+AI系统+详细图文搭建教程/支持GPT4/AI绘画/H5端/完整Prompt知识库
  • 本地启动若依微服务版本
  • HTML的span标签的作用是什么?答:对文本内容进行精细的样式化和标记。
  • 基于微服务、Java、Springcloud、Vue、MySQL开发的智慧工地管理系统源码
  • Redis内存策略
  • 视频监控/视频汇聚/视频云存储EasyCVR平台HLS流集成在小程序无法播放问题排查
  • vue3将通用组件注册成全局组件
  • 一文速学-让神经网络不再神秘,一天速学神经网络基础-前向传播(三)