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

C++第三方库【JSON】nlohman/json

文章目录

  • 优势
  • 使用
  • API
    • 从文件中读取json
    • 从json文本创建json对象
    • 直接创建并操作json对象
    • 字符串 <=> json对象
    • 文件流 <=> json对象
    • 从迭代器读取
    • 像使用STL一样的访问
    • STL容器转化为 json数组
    • STL容器 转 json对象
    • 自定义类型转化为 json对象
  • 限制

优势

  • 直观的语法:json的使用像是使用一个STL容器
  • 简单的引入:仅需要包含一个json.hpp头文件,不需要库,没有子项目,没有依赖项,没有复杂的构建系统。使用原版C++11编写。加快开发速度
  • 内存效率:经过严格的单元测试,没有内存泄露;每个JSON对象的开销为一个指针和一个枚举元素(1个字节)。默认泛化使用以下C++数据类型:字符串、数字、对象、数组、布尔值。但也可以根据需要对Generalized类进行模板化(std::string、int64_t、uint64_t、double、std::map、std::vectort、bool、basic_json)

使用

直接包含

dir/
└── nlohmann├── json_fwd.hpp└── json.hpp
└── a.cpp

一般只要包含json.hpp,如果需要forward-declarations,那么可以包含json_fwd.hpp

注意,因为库使用了C++11,所以编译的时候需要使用C++11以上的标准编译

#include <iostream>
#include "nlohmann/json.hpp"using json = nlohmann::json;int main()
{// 使用不同类型的默认值创建JSON值json j_null(json::value_t::null);json j_boolean(json::value_t::boolean);json j_number_integer(json::value_t::number_integer);json j_number_float(json::value_t::number_float);json j_object(json::value_t::object);json j_array(json::value_t::array);json j_string(json::value_t::string);// 序列化JSON值std::cout << j_null << '\n';std::cout << j_boolean << '\n';std::cout << j_number_integer << '\n';std::cout << j_number_float << '\n';std::cout << j_object << '\n';std::cout << j_array << '\n';std::cout << j_string << '\n';
}

运行结果:

$./a.out 
null
false
0
0.0
{}
[]
""

API

从文件中读取json

自动解析文件中的JSON,创建一个json对象

#include <fstream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;std::ifstream f("example.json");
json data = json::parse(f);

从json文本创建json对象

假设要通过下述的json文本创建json对象

{"pi": 3.141,"happy": true
}

方法:

// 使用原始字符串
json ex1 = json::parse(R"({"pi": 3.141,"happy": true}
)");// 直接赋值字符串,需要带上_json !!!
using namespace nlohmann::literals;
json ex2 = R"({"pi": 3.141,"happy": true}
)"_json;// 使用列表初始化
json ex3 = {{"happy", true},{"pi", 3.141},
};

直接创建并操作json对象

假设要通过下述json文本创建json对象
注意:不能带注释,对象/数组的最后一个元素后不要有,(逗号)

{"pi": 3.141,"happy": true,"name": "Niels","nothing": null,"answer": {"everything": 42},"list": [1, 0, 2],"object": {"currency": "USD","value": 42.99}
}

构建方法:

// 创建一个空的结构体
json j;// 添加一个存储为double的数字(注意j到object的转换)
j["pi"] = 3.141;// 添加一个bool值,存储为bool
j["happy"] = true;// 添加一个字符串,存储为std::string
j["name"] = "Niels";// 添加null对象
j["nothing"] = nullptr;// 添加嵌套对象
j["answer"]["everything"] = 42;// 添加一个数组,存储为std::vector(列表初始化)
j["list"] = { 1, 0, 2 };// 添加另一个对象(使用列表初始化)
j["object"] = { {"currency", "USD"}, {"value", 42.99} };// 直接通过列表创建
json j2 = {{"pi", 3.141},{"happy", true},{"name", "Niels"},{"nothing", nullptr},{"answer", {{"everything", 42}}},{"list", {1, 0, 2}},{"object", {{"currency", "USD"},{"value", 42.99}}}
};

字符串 <=> json对象

字符串 => json对象
从字符串反序列化到 json 对象,需要使用_json

// create object from string literal
json j = "{ \"happy\": true, \"pi\": 3.141 }"_json;// or even nicer with a raw string literal
auto j2 = R"({"happy": true,"pi": 3.141}
)"_json;

如果不加 _json,则不会解析传递的字符串文本,而只是用作 json 字符串。
使用 _json 需要先展开命名空间

using namespace nlohman::literals

上述例子同样可以使用 json::parse() 转化

auto j3 = json::parse(R"({"happy": true, "pi": 3.141})");

json对象 => 字符串

std::string s = j.dump();    // {"happy":true,"pi":3.141}// 序列化到好看的格式
// 传入要缩进的空格数
std::cout << j.dump(4) << std::endl;
// {
//     "happy": true,
//     "pi": 3.141
// }

注意序列化和赋值的区别

// 存储一个字符串
json j_string = "this is a string";// 转化为字符串导出
auto cpp_string = j_string.template get<std::string>();
// 适配变量的类型导出(当变量已存在时为 alternative)
std::string cpp_string2;
j_string.get_to(cpp_string2);// 序列化
std::string serialized_string = j_string.dump();// 这三个字符串是相等的
std::cout << cpp_string << " == " << cpp_string2 << " == " << j_string.template get<std::string>() << '\n';
// 这两个字符串是相等的
std::cout << j_string << " == " << serialized_string << std::endl;

该库仅支持 UTF-8。当在库中存储不同编码的字符串时,调用dump可能会引发异常json::error_handler_t::replacejson::error_handler_t::ignore

文件流 <=> json对象

还可以使用 streams 进行序列化和反序列化:

// 从标准输入反序列化
json j;
std::cin >> j;// 通过标准输出序列化
std::cout << j;// 格式控制,重载了setw
std::cout << std::setw(4) << j << std::endl;

也适用于 stream 的子类。比如std::istreamstd::ostream

// 读一个json文件
std::ifstream i("file.json");
json j;
i >> j;// 将美化的json写到另一个文件
std::ofstream o("pretty.json");
o << std::setw(4) << j << std::endl;

从迭代器读取

还可以从迭代器范围解析 JSON
从迭代器可访问的任何容器中,其整数类型为 1、2 或 4 字节,将分别解释为 UTF-8、UTF-16 和 UTF-32。例如uint8_t、uint16_t

std::vector<std::uint8_t> v = {'t', 'r', 'u', 'e'};
json j = json::parse(v.begin(), v.end());

像使用STL一样的访问

// 通过push_back创建数组
json j;
j.push_back("foo");
j.push_back(1);
j.push_back(true);// 也可以emplace_back
j.emplace_back(1.78);// 通过迭代器访问json数组
for (json::iterator it = j.begin(); it != j.end(); ++it) {std::cout << *it << '\n';
}// 范围for
for (auto& element : j) {std::cout << element << '\n';
}// 访问和设置
const auto tmp = j[0].template get<std::string>();
j[1] = 42;
bool foo = j.at(2);// 比较
j == R"(["foo", 1, true, 1.78])"_json;  // true// 其他方法
j.size();     // 4 entries
j.empty();    // false
j.type();     // json::value_t::array
j.clear();    // the array is empty again// 类型检查
j.is_null();
j.is_boolean();
j.is_number();
j.is_object();
j.is_array();
j.is_string();// 创建对象
json o;
o["foo"] = 23;
o["bar"] = false;
o["baz"] = 3.141;// 也可以使用emplace
o.emplace("weather", "sunny");// 对象迭代器
for (json::iterator it = o.begin(); it != o.end(); ++it) {std::cout << it.key() << " : " << it.value() << "\n";
}// 范围for
for (auto& el : o.items()) {std::cout << el.key() << " : " << el.value() << "\n";
}// 结构化绑定
for (auto& [key, value] : o.items()) {std::cout << key << " : " << value << "\n";
}// 查找元素
if (o.contains("foo")) {// there is an entry with key "foo"
}// 查找到结尾
if (o.find("foo") != o.end()) {// there is an entry with key "foo"
}// 返回个数
int foo_present = o.count("foo"); // 1
int fob_present = o.count("fob"); // 0// 删除元素
o.erase("foo");

STL容器转化为 json数组

  std::vector<int> c_vector{1, 2, 3, 4};json j_vec(c_vector);std::cout << j_vec << '\n';std::deque<double> c_deque{1.2, 2.3, 3.4, 5.6};json j_deque(c_deque);std::cout << j_deque << '\n';std::list<bool> c_list{true, true, false, true};json j_list(c_list);std::cout << j_list << '\n';std::forward_list<int64_t> c_flist{12345678909876, 23456789098765,34567890987654, 45678909876543};json j_flist(c_flist);std::cout << j_list << '\n';std::array<unsigned long, 4> c_array{{1, 2, 3, 4}};json j_array(c_array);std::cout << j_array << '\n';std::set<std::string> c_set{"one", "two", "three", "four", "one"};json j_set(c_set); // 只有一个"one"std::cout << j_set << '\n';std::unordered_set<std::string> c_uset{"one", "two", "three", "four", "one"};json j_uset(c_uset); // 只有一个"one"std::cout << j_uset << '\n';std::multiset<std::string> c_mset{"one", "two", "one", "four"};json j_mset(c_mset); // 有多个"one"std::cout << j_mset << '\n';std::unordered_multiset<std::string> c_umset{"one", "two", "one", "four"};json j_umset(c_umset); // 有多个"one"std::cout << j_umset << '\n';

STL容器 转 json对象

  std::map<std::string, int> c_map{{"one", 1}, {"two", 2}, {"three", 3}};json j_map(c_map);std::cout << j_map << '\n';std::unordered_map<const char *, double> c_umap{{"one", 1.2}, {"two", 2.3}, {"three", 3.4}};json j_umap(c_umap);std::cout << j_umap << '\n';std::multimap<std::string, bool> c_mmap{{"one", true}, {"two", true}, {"three", false}, {"three", true}};json j_mmap(c_mmap); // 只有一个"three"对象std::cout << j_mmap << '\n';std::unordered_multimap<std::string, bool> c_ummap{{"one", true}, {"two", true}, {"three", false}, {"three", true}};json j_ummap(c_ummap); // 只有一个"three"对象std::cout << j_ummap << '\n';

自定义类型转化为 json对象

假设有如下类

namespace ns{struct person {std::string name;std::string address;int age;};
}

实现如下两个方法,即可支持 person 直接转化为 json 对象

using json = nlohmann::json;namespace ns{void to_json(json& j, const person& p) {j = json{{"name", p.name}, {"address", p.address}, {"age", p.age}};}void from_json(const json& j, person& p) {j.at("name").get_to(p.name);j.at("address").get_to(p.address);j.at("age").get_to(p.age);}
}

即可

// 创建一个person对象
ns::person p {"Ned Flanders", "744 Evergreen Terrace", 60};// 将 person 对象转化为 json 对象
json j = p;std::cout << j << std::endl;
// {"address":"744 Evergreen Terrace","age":60,"name":"Ned Flanders"}// 将 json 对象转化为 person 对象
auto p2 = j.template get<ns::person>();// 相等的
assert(p == p2);

注意:

  • to_jsonfrom_json 必须要位于要适配的自定义类的命名空间,不然库找不到,示例中都放到了 ns 中
  • 在方法中,使用at(),而不是.,如果键不在,会引发异常以便处理
  • 必须都为内置类型,自定义类型还需要实现上述两个方法

限制

  • 只支持UTF-8作为输入
  • 不支持json注释
  • 默认不保证 json 中 key 的顺序,即打印的key的顺序是随机的。如果要支持,使用 nlohmann::ordered_json 试试。

以上就是本篇博客的所有内容,感谢你的阅读
如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要。
在这里插入图片描述

相关文章:

C++第三方库【JSON】nlohman/json

文章目录 优势使用API从文件中读取json从json文本创建json对象直接创建并操作json对象字符串 <> json对象文件流 <> json对象从迭代器读取像使用STL一样的访问STL容器转化为 json数组STL容器 转 json对象自定义类型转化为 json对象 限制 优势 直观的语法&#xff…...

超细的ollama下载以及本地部署deepseek项目

Ollama 是一个开源的本地化大语言模型&#xff08;LLM&#xff09;运行和部署工具&#xff0c;专注于让开发者能够快速、高效地在本地运行和管理各种开源大语言模型&#xff08;如 LLaMA、Mistral、GPT 系列等&#xff09;。它提供了一个统一的接口&#xff0c;简化了模型下载、…...

【Sequelize】关联模型和孤儿记录

一、关联模型的核心机制 1. 关联类型与组合规则 • 基础四类型&#xff1a; • hasOne&#xff1a;外键存储于目标模型&#xff08;如用户档案表存储用户ID&#xff09; • belongsTo&#xff1a;外键存储于源模型&#xff08;如订单表存储用户ID&#xff09; • hasMany&…...

Sentinel实战教程:流量控制与Spring Boot集成

Sentinel实战教程:流量控制与Spring Boot集成 1. Sentinel简介与核心概念 1.1 什么是Sentinel? Sentinel是阿里巴巴开源的流量控制组件,主要用于微服务架构中的流量防护。它通过限流、熔断、热点防护等机制,帮助系统在高并发场景下保持稳定运行。 1.2 核心功能与术语 流…...

编程技能:调试01,调试介绍

专栏导航 本节文章分别属于《Win32 学习笔记》和《MFC 学习笔记》两个专栏&#xff0c;故划分为两个专栏导航。读者可以自行选择前往哪个专栏。 &#xff08;一&#xff09;WIn32 专栏导航 上一篇&#xff1a;编程基础&#xff1a;位运算07&#xff0c;右移 回到目录 下一…...

循环神经网络 - 扩展到图结构之递归神经网络

本文我们来学习递归神经网络(Recursive Neural Network&#xff0c;RecNN)&#xff0c;其是循环神经网络在有向无循环图上的扩展 。 递归神经网络是一类专门设计来处理具有层次结构或树形结构的数据的神经网络模型。它与更常见的循环神经网络&#xff08;Recurrent Neural Net…...

【Kubernetes基础--Pod深入理解】--查阅笔记2

深入理解Pod 为什么要有个Pod1. 容器协作与资源共享2. 简化调度和资源管理3. 设计模式支持 Pod 基本用法Pod 容器共享 VolumePod 的配置管理ConfigMap 概述创建 ConfigMap 资源对象在 Pod 中使用 ConfigMap使用 ConfigMap 的限制条件 为什么要有个Pod Pod 的引入并非技术冗余&…...

【euclid】10.3 2D变换模块(transform2d.rs)bytemuck trait

这段代码是一个 Rust 的 unsafe trait 实现&#xff0c;用于标记 Transform2D 类型在特定条件下可以安全地被视为由全零字节组成的有效实例。让我们详细解释每个部分&#xff1a; 代码分解&#xff1a; #[cfg(feature "bytemuck")] unsafe impl<T: Zeroable, S…...

Maven超级详细安装部署

1.到底什么是Maven&#xff1f;搞清楚这个 Maven 是一个项目管理工具&#xff0c;主要用于 Java 项目的构建、依赖管理和文档生成。 它基于项目对象模型&#xff08;POM&#xff09;&#xff0c;通过 pom.xml 文件定义项目的配置。 &#xff08;简单说破&#xff1a;就是工程…...

C# + Python混合开发实战:优势互补构建高效应用

文章目录 前言&#x1f94f;一、典型应用场景1. 桌面应用智能化2. 服务端性能优化3. 自动化运维工具 二、四大技术实现方案方案1&#xff1a;进程调用&#xff08;推荐指数&#xff1a;★★★★☆&#xff09;方案2&#xff1a;嵌入Python解释器&#xff08;推荐指数&#xff1…...

云服务模式全知道:IaaS、PaaS、SaaS与DaaS深度解析

云服务模式详解&#xff1a;IaaS、PaaS、SaaS与DaaS 在当今数字化快速发展的时代&#xff0c;云计算已经成为企业和开发者不可或缺的一部分。它提供了灵活的资源和服务&#xff0c;使得用户可以根据自己的需求选择最合适的解决方案。本文将详细介绍四种主要的云服务模式&#…...

电机控制-隆博戈观测器(Luenberger state observer)

本文围绕基于无传感器控制策略的状态观测器展开&#xff0c;介绍其在电机领域的应用、原理、性能表现及无传感器驱动的优劣&#xff1a; 应用场景&#xff1a;适用于燃油泵、风扇等大量固定转速和低成本应用场景。工作原理&#xff1a;状态观测器利用完整的电机微分模型&#…...

RK3506+net9+VS2022跨平台调试C#程序

下载GetVsDbg.sh &#xff0c;这脚本会下载一个压缩包&#xff0c;然后解压缩&#xff0c;设置x权限等等。但是目标板子连不上&#xff0c;就想办法获取到下载路径&#xff0c;修改这个脚本&#xff0c;显示这个下载链接后&#xff0c;复制一下&#xff0c;用电脑下下来 修改好…...

【16】数据结构之基于树的排序算法篇章

目录标题 选择排序简单选择排序树形选择排序 堆排序堆的定义Heap小跟堆大根堆堆的存储堆的代码设计堆排序的代码设计 排序算法综合比较 选择排序 基本思想&#xff1a;从待排序的序列中选出最大值或最小值&#xff0c;交换该元素与待排序序列的头部元素&#xff0c;对剩下的元…...

华熙生物亮相消博会,这次又带来了什么样的变化?

首先&#xff0c;从展示层面来看&#xff0c;华熙生物在消博会上构建科技桥梁&#xff0c;展台主视觉展示糖生物学发展历程与自身发展交织历程&#xff0c;这象征着中国生物科技企业从产业突围到定义全球标准的蜕变。这一展示不仅提升了华熙生物的品牌形象&#xff0c;更向外界…...

python自动化浏览器标签页的切换

#获取全部标签页的句柄返回句柄的列表 handleswebdriver.window_handles#获取全部标签页的句柄返回句柄的列表 print(len(handles)) 切换标签页 handleswebdriver.window_handles webdriver.switch_to.window(handles[index])#切换到第几个标签页就写几 关闭标签页 关闭标…...

大象机器人推出myCobot 280 RDK X5,携手地瓜机器人共建智能教育机

摘要 大象机器人全新推出轻量级高性能教育机械臂 myCobot 280 RDK X5&#xff0c;该产品集成地瓜机器人 RDK X5 开发者套件&#xff0c;深度整合双方在硬件研发与智能计算领域的技术优势&#xff0c;实现芯片架构、软件算法、硬件结构的全栈自主研发。作为国内教育机器人生态合…...

Redis 数据类型全解析:从基础到实战应用

精心整理了最新的面试资料和简历模板&#xff0c;有需要的可以自行获取 点击前往百度网盘获取 点击前往夸克网盘获取 Redis 作为高性能的键值对存储系统&#xff0c;其丰富的数据类型是实现复杂业务逻辑的核心优势。本文将深入解析 Redis 六大核心数据类型及扩展类型&#xff…...

第一天 unity3D 引擎入门

一、为什么选择Unity进行3D开发&#xff1f; Unity作为全球使用最广泛的游戏引擎&#xff0c;在2022年的开发者调查中占据了62%的市场份额。它不仅支持3D/2D游戏开发&#xff0c;更在VR/AR、工业仿真、影视动画等领域大放异彩。对于初学者而言&#xff0c;Unity的独特优势在于…...

【初阶数据结构】——算法复杂度

一、前言 1、数据结构是什么&#xff1f; 数据结构(Data Structure)是计算机存储、组织数据的⽅式&#xff0c;指相互之间存在⼀种或多种特定关系的数 据元素的集合。没有⼀种单⼀的数据结构对所有⽤途都有⽤&#xff0c;所以我们要学各式各样的数据结构&#xff0c; 如&…...

MySQL:存储函数和存储过程

系列文章目录 1.MySQL编程基础 2.程序控制流语句 3.存储过程 4.游标 5.嵌入式SQL 文章目录 系列文章目录前言一、程序控制流语句&#xff1a;二、存储函数&#xff1a; 1.存储函数的特点&#xff1a;2.存储函数的定义&#xff1a;3.调用存储函数 三、存储过程&#xff1a;…...

常见的 API 设计风格

在软件开发中&#xff0c;常见的 API 设计风格主要有以下几种&#xff0c;每种风格适用于不同的场景和需求&#xff1a; 1. RESTful API (主流) 特点&#xff1a; 基于 HTTP 协议&#xff0c;使用标准方法&#xff08;GET/POST/PUT/DELETE&#xff09;资源导向&#xff08;UR…...

Google-A2A协议全面解析:一文掌握Agent-to-Agent协议的核心与应用

前言&#xff1a; 在当今人工智能技术飞速发展的时代&#xff0c;智能体&#xff08;Agent&#xff09;已悄然融入我们生活的各个角落。无论是个人智能助手&#xff0c;还是企业的自动化工具&#xff0c;各类AI代理的应用愈发广泛。但目前这些智能体之间大多处于孤立状态&…...

Linux-服务器添加审计日志功能

#查看audit软件是否在运行(状态为active而且为绿色表示已经在运行) systemctl start auditd #如果没有在运行的话,查看是否被系统禁用 (audit为0表示被禁用) cat /proc/cmdline | grep -w "audit=0" #修改/etc/default/grub里面audit=0 改为audit=1 #更新GRUB…...

基于机器视觉的多孔零件边缘缺陷检测(源码C++、opencv、凸包、凸缺陷检测)

&#x1f451;主页&#xff1a;吾名招财 &#x1f453;简介&#xff1a;工科学硕&#xff0c;研究方向机器视觉&#xff0c;爱好较广泛… ​&#x1f4ab;签名&#xff1a;面朝大海&#xff0c;春暖花开&#xff01; 基于机器视觉的多孔零件边缘缺陷检测&#xff08;源码C、ope…...

汇川PLC通信

汇川PLC通信协议及读写 引言 汇川PLC&#xff08;Programmable Logic Controller&#xff0c;可编程逻辑控制器&#xff09;广泛应用于工业自动化领域。汇川PLC支持多种通信协议&#xff0c;包括Modbus、Ethernet/IP、PPI等。本文将详细介绍汇川PLC的通信协议&#xff0c;并通…...

如何使用AI辅助开发CSS3 - 通义灵码功能全解析

一、引言 CSS3 作为最新的 CSS 标准&#xff0c;引入了众多新特性&#xff0c;如弹性布局、网格布局等&#xff0c;极大地丰富了网页样式的设计能力。然而&#xff0c;CSS3 的样式规则繁多&#xff0c;记忆所有规则对于开发者来说几乎是不可能的任务。在实际开发中&#xff0c…...

MySQL入门:数据表的创建

​今天我们来介绍一下除HTML外的另一种语言&#xff1a;MySQL语言&#xff1b; MySQL&#xff1a;即一种用于管理和处理关系数据库的标准语言。要用于执行查询、更新、管理数据库中的数据以及定义和操作数据库结构。 接下来我会逐一介绍它的作用以及其中数据表&#xff0c;数据…...

数据库的基本原则

数据库的核心原则 原子性与持久性&#xff1a;原子性&#xff08;Atomicity&#xff09;确保一个事务中的所有操作要么全部完成&#xff0c;要么完全不执行&#xff0c;不会出现部分完成的情况。持久性&#xff08;Durability&#xff09;则保证一旦事务提交成功&#xff0c;即…...

Rust 中的Relaxed 内存指令重排演示:X=0 Y=0 是怎么出现的?

&#x1f525; Rust 中的内存重排演示&#xff1a;X0 && Y0 是怎么出现的&#xff1f; 在并发编程中&#xff0c;我们经常会听说“内存重排&#xff08;Memory Reordering&#xff09;”这个术语&#xff0c;但它似乎总是只出现在理论或者别人口中的幻觉里。本文将通过…...