一.认识json
JSON(JavaScrip Object Notation)是一种轻量级的数据交换格式。
可以精简为一句话:Json是一种数据格式。和语言无关,在什么语言中都可以使用Json。基于这种通用的数据格式,一般处理两方面的任务:
- 组织数据(数据序列化),用于数据的网络传输
- 组织数据(数据序列化),写磁盘文件实现数据的持久化存储(一般以.json作为文件后缀)
Json中主要有两种数据格式:Json数组和Json对象,并且这两种格式可以交叉嵌套使用,下面依次介绍下这两种数据格式:
二.json使用
1.json数组
Json数组使用 [] 表示,[]里边是元素,元素和元素之间使用逗号间隔,最后一个元素后边没有逗号,一个Json数组中支持同时存在多种不同类型的成员,包括:整形、 浮点、 字符串、 布尔类型、 json数组、 json对象、 空值-null
。由此可见Json数组比起C/C++数组要灵活很多。
- Json数组中的元素数据类型一致
// 整形
[1,2,3,4,5]
// 字符串
["luffy", "sanji", "zoro", "nami", "robin"]
- Json数组中的元素数据类型不一致
[12, 13.34, true, false, "hello,world", null]
- Json数组中的数组嵌套使用
[
["cat", "dog", "panda", "beer", "rabbit"],
["北京", "上海", "天津", "重庆"],
["luffy", "boy", 19]
]
- Json数组和对象嵌套使用
[
{
"luffy":{
"age":19,
"father":"Monkey·D·Dragon",
"grandpa":"Monkey D Garp",
"brother1":"Portgas D Ace",
"brother2":"Sabo"
}
}
]
2.json对象
Json对象使用 {} 来描述,每个Json对象中可以存储若干个元素,每一个元素对应一个键值对(key:value 结构),元素和元素之间使用逗号间隔,最后一个元素后边没有逗号。对于每个元素中的键值对有以下细节需要注意:
- 键值(key)必须是字符串,位于同一层级的键值不要重复(因为是通过键值取出对应的value值)
- value值的类型是可选的,可根据实际需求指定,可用类型包括:
整形、 浮点、 字符串、 布尔类型、 json数组、 json对象、 空值-null
。
使用Json对象描述一个人的信息:
{
"Name":"Ace",
"Sex":"man",
"Age":20,
"Family":{
"Father":"Gol·D·Roger",
"Mother":"Portgas·D·Rouge",
"Brother":["Sabo", "Monkey D. Luffy"]
},
"IsAlive":false,
"Comment":"yyds"
}
3.注意事项
- json对象或json数组中的元素之间用
,
隔开,最后一个元素不需要,
- json对象中元素的键必须为字符串且不重复
- 重点:在一个Json文件中只能有一个Json数组或者Json对象的根节点,不允许同时存储多个并列的根节点。
错误的写法:
// test.json
{
"name":"luffy",
"age":19
}
{
"user":"ace",
"passwd":"123456"
}
错误原因:在一个Json文件中有两个并列的Json根节点(并列包含Json对象和Json对象、Json对象和Json数组、Json数组和Json数组),根节点只能有一个。
正确的写法:
// test.json
{
"Name":"Ace",
"Sex":"man",
"Age":20,
"Family":{
"Father":"Gol·D·Roger",
"Mother":"Portgas·D·Rouge",
"Brother":["Sabo", "Monkey D. Luffy"]
},
"IsAlive":false,
"Comment":"yyds"
}
三.json理解(自己慢慢摸索)
1.json常见库
C++要想使用json,必须开始导入对应的头目和库文件,常用的C++对应库文件有以下几种:
- RapidJSON:
- 这是一个非常流行的C++ JSON库,它提供了快速且易于使用的接口。
- 导入头文件的方式通常是将RapidJSON的头文件包含到您的项目中。例如:
#include "rapidjson/document.h"
- nlohmann/json:
- 这个库以其简洁的API和良好的文档而受到许多开发者的喜爱。
- 导入头文件的方式是:
#include "nlohmann/json.hpp"
- jsoncpp:
- jsoncpp是一个功能丰富的库,支持多种数据类型和流操作。
- 导入头文件的方式通常是:
#include "json/json.h"
- sonic-cpp:
- 这是由字节跳动自研的高性能JSON库,它利用向量化指令和优化内存布局来提高性能。
- 导入头文件的方式可能需要查看该库的具体文档来确定。
- jsonxx:
- 这是一个轻量级的JSON库,支持JSON解析和序列化。
- 导入头文件的方式可能是:
#include "jsonxx/jsonxx.h"
2.json代码操作
这里我们选择第二种库文件,即nlohmann/json
,假设在已导入对应头目和库文件的基础下:
json数组:
json empty_array_explicit = json::array(); //创建一个空的json数组
empty_array_explicit.push_back(1); // 添加一个整数
empty_array_explicit.push_back("example"); // 添加一个字符串
empty_array_explicit.push_back(true); // 添加一个布尔值
json对象:
json s; //默认创建的是一个空的json对象
//第一种添加元素方式
s["key3"] = true; // 添加一个布尔值
s["key4"] = {1, 2, 3}; // 添加一个数组
s["key5"] = {{"subkey1", "subvalue1"}, {"subkey2", "subvalue2"}}; // 添加一个嵌套对象
//第二种直接定义方式
json j2 = {
{"pi", 3.141},
{"happy", true},
{"name", "Niels"},
{"nothing", nullptr},
{"answer", {
{"everything", 42}
}},
{"list", {1, 0, 2}},
{"object", {
{"currency", "USD"},
{"value", 42.99}
}}
};
3.静态成员函数
对于 json empty_array_explicit = json::array();
这行代码,它创建了一个空的 JSON 数组。这里的 json::array()
是一个静态成员函数,它返回一个空的 JSON 数组。
在 nlohmann/json
中,json
类提供了几个静态成员函数,这些函数允许您直接创建特定类型的 JSON 值,而不需要先创建一个 json
对象。这些静态成员函数包括:
json::object()
: 创建一个空的 JSON 对象。json::array()
: 创建一个空的 JSON 数组。json::null()
: 创建一个 JSONnull
值。json::parse(std::string const&)
: 解析 JSON 字符串。json::parse(std::istream&)
: 从输入流中解析 JSON 数据。json::string()
: 创建一个 JSON 字符串。json::number_integer()
和json::number_unsigned()
: 创建整数和无符号整数类型的 JSON 数值。json::boolean()
: 创建布尔类型的 JSON 值。
注意,可以以json()
的类构造函数可以使用初始化列表的方式,建立json对象:
json object_with_data = json({
{"key1", "value1"},
{"key2", 42},
{"key3", true}
});
4.序列化和反序列化
通过字符串创建json对象(反序列化):
json j = "{ \"happy\": true, \"pi\": 3.141 }"_json;
在 nlohmann/json
库中,"_json"
是一个后缀操作符,它用于将字符串字面量转换为 json
对象。这个后缀操作符是 nlohmann/json
库特有的,它允许您直接从字符串字面量创建 json
对象,而不需要调用解析函数。
所以,这行代码的意思是:
- 创建一个字符串字面量:
"{ \"happy\": true, \"pi\": 3.141 }"
。 - 使用
_json
后缀操作符将这个字符串字面量转换为json
对象。 - 将转换后的
json
对象赋值给变量j
。
字符串字面量
"{ \"happy\": true, \"pi\": 3.141 }"
中的反斜杠\
用于转义双引号"
。在 JSON 字符串中,双引号用于标识字符串的开始和结束,因此它们是特殊字符。当您需要在 JSON 字符串内部包含双引号时,您必须使用转义序列\"
来表示一个双引号字符。
如果,用上C++11的原始字符变量,可以改写成:
auto j2 = R"(
{
"happy": true,
"pi": 3.141
}
)"_json;
获取 JSON 值的字符串表示形式(序列化):
std::string s = j.dump(); // {"happy":true,"pi":3.141}
std::cout << j.dump(4) << std::endl; //这里的dump(4)中的4表示4个空格一个缩进
j.dump()
方法被调用来将json
对象j3
序列化(转换)回 JSON 字符串格式。dump
方法返回一个std::string
类型的值,包含了序列化的 JSON 数据。- 这个序列化的 JSON 字符串被赋值给变量
s
。在这个例子中,s
的值将是"{\"happy\":true,\"pi\":3.141}"
,这是一个 JSON 格式的字符串,表示一个对象,其中"happy"
的值是布尔值true
,"pi"
的值是数值3.141
。
5.成员方法
以下是一些常用的 json
类成员方法:
.dump()
:
- 将
json
对象序列化为 JSON 字符串。可以指定格式化选项,如缩进。
.parse()
:
- 解析 JSON 字符串,创建对应的
json
对象。
.get_ref()
:
- 获取对
json
对象内部数据的引用,这在需要直接修改json
对象的底层数据时很有用。
.at(size_type index)
:
- 通过索引访问 JSON 数组中的元素。如果索引无效,会抛出异常。
.at(key)
:
- 通过键名访问 JSON 对象中的元素。如果键不存在,会抛出异常。
[size()]
:
- 用于访问 JSON 数组中的元素,类似于下标操作符。
["key"]
:
- 用于访问 JSON 对象中的元素,通过键名。如果键不存在,会创建一个新元素。
.erase(key)
:
- 删除 JSON 对象中的指定键。
.push_back(value)
:
- 向 JSON 数组中添加一个新元素。
.emplace_back(key, value)
:
- 在 JSON 数组的末尾就地构造一个新元素。
.emplace(key, value)
:
- 在 JSON 对象中就地构造一个新元素。
.dump(std::ostream&)
:
- 将 JSON 对象序列化并输出到提供的输出流。
.dump(std::ostream&, int indent)
:
- 将 JSON 对象序列化并输出到提供的输出流,
indent
参数用于指定缩进级别。
.dump(std::string&, int indent)
:
- 将 JSON 对象序列化到字符串中,
indent
参数用于指定缩进级别。
.type()
:
- 返回
json
对象的类型。
.is_null()
,.is_boolean()
,.is_number()
,.is_string()
,.is_array()
,.is_object()
:
- 分别用于检查
json
对象是否为null
、布尔值、数值、字符串、数组或对象。
这些方法提供了对 JSON 数据的全面操作,包括创建、解析、访问、修改和序列化。
6.到/从流
int main() {
json j;
std::cin >> j;
std::cout << std::setw(4) << j << std::endl; //设置输出流的宽度是4个字符串
return 0;
}
四.配置json环境
以下是将 nlohmann/json
库集成到 Visual Studio 2022 的步骤:
- 下载库文件:
- 访问
nlohmann/json
的 GitHub 仓库:https://github.com/nlohmann/json - 在 "Releases" 部分找到最新的稳定版本。
- 下载
include.zip
文件。
- 解压文件:
- 解压
include.zip
文件到您的工程文件夹下,或者任何您希望存放库文件的位置。
- 修改工程属性:
- 在 Visual Studio 2022 中,打开您的项目。
- 右键点击项目名称,选择 "Properties"(属性)。
- 在 "Configuration Properties"(配置属性)下,选择 "C/C++",然后点击 "General"(常规)。
- 在 "Additional Include Directories"(附加包含目录)中,添加解压后的
include
目录的路径。例如,如果您将include
目录解压到了C:\libs\nlohmann_json
,则添加C:\libs\nlohmann_json\include
。
- 测试:
- 在您的源代码文件中,添加以下代码来测试库是否正确导入:
#include <iostream>
#include "nlohmann/json.hpp"
using json = nlohmann::json;
int main() {
json j;
// 首先创建一个空的 json 对象
j["pi"] = 3.141;
// 然后通过名称/值对的方式进行初始化
std::cout << j.dump(4) << std::endl;
return 0;
}
- 编译并运行您的项目,如果一切正常,您应该能看到 JSON 对象被正确创建和打印。