GitHub地址 https://github.com/nlohmann/json
什么是 JSON
JSON 其实就是一种约定好的数据表示形式。我们按照这种 JSON 格式发送字符串,对面再按照这种格式解析得到想要的信息。
{
"name":"zhang san",
"age":16,
"friend":["li si", "wang wu"]
}
怎么理解 JSON 的「序列化」和「反序列化」呢?所谓的序列化就是将对象的状态转换为可保持或者输出的格式的过程,反序列化,就是将流转换为对象。上面的 JSON 案例就是将某个 JSON 对象序列化的结果,反序列化就是将上面的 JSON 案例转换成一个 JSON 对象。然后我们可以从 JSON 对象中获取某个键值对。
JSON for Modern C++
JSON for Modern C++
是一个德国大牛nlohmann写的,该版本的 JSON 有以下特点:
- 直观的语法。
- 整个代码由一个头文件组成 json.hpp,没有子项目,没有依赖关系,没有复杂的构建系统,使用起来非常方便。
- 使用 C++11标准编写。
- 使用 JSON 像使用 STL 容器一样。
- STL 和 JSON 容器之间可以相互转换。
可以看到整个整个实现都放在了 json.hpp 中,我们只要包含这个头文件就可以使用。
使用案例
以下都是GitHub项目给出的案例,我从中挑选了一些感兴趣的。
创建JSON对象
假设你想要创建以下的 JSON 格式
{
"pi": 3.141,
"happy": true,
"name": "Niels",
"nothing": null,
"answer": {
"everything": 42
},
"list": [1, 0, 2],
"object": {
"currency": "USD",
"value": 42.99
}
}
#include "json.hpp"
using json = nlohmann::json; // 这里将作用域简短化成json
#include <iostream>
#include <string>
#include <unordered_map>
int main()
{
json js; // 生成一个json对象
js["msg_type"] = 2;
js["from"] = "zhang san";
js["to"] = "li si";
js["app"] = {"webapp", "wechat"};
// 我们可以直接打印序列化的字符串
// {"app":["webapp","wechat"],"from":"zhang san","msg_type":2,"to":"li si"}
std::cout << js << std::endl;
return 0;
}
从文件中读取JSON
{
"name":"syz",
"married":false,
"friend":["zhang san", "li si"]
}
#include <fstream>
#include <iostream>
#include "json.hpp"
using json = nlohmann::json;
int main()
{
std::ifstream f("example.json"); // 打开一个文件
json data = json::parse(f);
std::cout << data["name"] << std::endl;
std::cout << data["married"] << std::endl;
std::cout << data["friend"] << std::endl;
// "syz"
// false
// ["zhang san","li si"]
return 0;
}
序列化/反序列化
获取序列化后的字符串形式
#include <iostream>
#include <string>
#include "json.hpp"
using json = nlohmann::json;
int main()
{
json j;
j["pi"] = 3.141;
j["happy"] = true;
j["list"] = { 1, 0, 2 };
// 获取序列化后的字符串
std::string serialization_str = j.dump();
// {"happy":true,"list":[1,0,2],"pi":3.141}
std::cout << serialization_str << std::endl;
return 0;
}
打印带有格式的序列化字符串
int main()
{
json j;
j["pi"] = 3.141;
j["happy"] = true;
// 打印带有格式的序列化字符串
// 传入参数为要缩进的空格数
std::cout << j.dump(4) << std::endl;
// {
// "happy": true,
// "pi": 3.141
// }
return 0;
}
类似STL的使用方式
#include <iostream>
#include <string>
#include "json.hpp"
using json = nlohmann::json;
int main()
{
json j;
j.push_back("foo");
j.push_back(1);
j.push_back(true);
j.emplace_back(1.78);
for (json::iterator it = j.begin(); it != j.end(); ++it) {
std::cout << *it << '\n';
}
for (const auto& element : j) {
std::cout << element << '\n';
}
return 0;
}
与STL容器的转换
std::vector<int> c_vector {1, 2, 3, 4};
json j_vec(c_vector);
// [1, 2, 3, 4]
std::deque<double> c_deque {1.2, 2.3, 3.4, 5.6};
json j_deque(c_deque);
// [1.2, 2.3, 3.4, 5.6]
std::array<unsigned long, 4> c_array {{1, 2, 3, 4}};
json j_array(c_array);
// [1, 2, 3, 4]
可以使用任何的关联容器去创建一个 JSON 对象。其「键」可以构造 std::string,其「值」可以构造一个 JSON 值。注意,在多映射的情况下,只有一个键被用于 JSON 对象,而值则取决于STL容器的内部顺序。
std::unordered_set<std::string> c_uset {"one", "two", "three", "four", "one"};
json j_uset(c_uset); // one 只能重复一次
// maybe ["two", "three", "four", "one"]
std::map<std::string, int> c_map { {"one", 1}, {"two", 2}, {"three", 3} };
json j_map(c_map);
// {"one": 1, "three": 3, "two": 2 }
std::unordered_map<const char*, double> c_umap { {"one", 1.2}, {"two", 2.3}, {"three", 3.4} };
json j_umap(c_umap);
// {"one": 1.2, "two": 2.3, "three": 3.4}