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

news2025/4/16 13:52:40

文章目录

  • 优势
  • 使用
  • 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 试试。

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

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

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

相关文章

超细的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 核心功能与术语 流…

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

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

Maven超级详细安装部署

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

电机控制-隆博戈观测器(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;更向外界…

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

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

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

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

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…

如何使用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;但它似乎总是只出现在理论或者别人口中的幻觉里。本文将通过…

C++进程间通信开发实战:高效解决项目中的IPC问题

C进程间通信开发实战&#xff1a;高效解决项目中的IPC问题 在复杂的软件项目中&#xff0c;进程间通信&#xff08;Inter-Process Communication, IPC&#xff09;是实现模块化、提高系统性能与可靠性的关键技术之一。C作为一门高性能的编程语言&#xff0c;广泛应用于需要高效…

FPGA-DDS技术的波形发生器

1.实验目的 1.1掌握直接数字频率合成&#xff08;DDS&#xff09;的基本原理及其实现方法。 1.2在DE2-115 FPGA开发板上设计一个可调频率的正弦波和方波发生器&#xff0c;频率范围10Hz~5MHz&#xff0c;最小分辨率小于1kHz。 1.3使用Quartus II进行仿真&#xff0c;并通过S…