3. nlohmann/json入门
nlohmann/json是一个开源的C++库,用于处理JSON数据。它提供了简单、直观的API,使得在C++中解析、创建和操作JSON数据变得非常方便。
这部分将会介绍nlohmann/json的基本用法,包括如何解析JSON数据、如何创建JSON数据、如何访问JSON数据、如何修改JSON数据、如何序列化JSON数据等。
3.1. 如何从文件中读取json数据
1ifstream f("example.json");
2nlohmann::json data = nlohmann::json::parse(f);
3/* nlohmann::json data;
4data >> f;*/
3.2. json作为第一类数据类型
以下是一些示例,可帮助您了解如何使用该类。
假设您要创建 JSON 对象:
1nlohmann::json data = {
2 {"pi", 3.141},
3 {"happy", true},
4 {"name", "Niels"},
5 {"nothing", nullptr},
6 {"answer", {
7 {"everything", 42}
8 }},
9 {"list", {1, 0, 2}},
10 {"object", {
11 {"currency", "USD"},
12 {"value", 42.99}
13 }}
14};
有了这个库,你可以写:
1// create an empty structure (null)
2json j;
3// add a number that is stored as double (note the implicit conversion of j to an object)
4j["pi"] = 3.141;
5// add a Boolean that is stored as bool
6j["happy"] = true;
7// add a string that is stored as std::string
8j["name"] = "Niels";
9// add another null object by passing nullptr
10j["nothing"] = nullptr;
11// add an object inside the object
12j["answer"]["everything"] = 42;
13// add an array that is stored as std::vector (using an initializer list)
14j["list"] = { 1, 0, 2 };
15// add another object (using an initializer list of pairs)
16j["object"] = { {"currency", "USD"}, {"value", 42.99} };
17// instead, you could also write (which looks very similar to the JSON above)
18json j2 = {
19 {"pi", 3.141},
20 {"happy", true},
21 {"name", "Niels"},
22 {"nothing", nullptr},
23 {"answer", {
24 {"everything", 42}
25 }},
26 {"list", {1, 0, 2}},
27 {"object", {
28 {"currency", "USD"},
29 {"value", 42.99}
30 }}
31};
请注意,在所有这些情况下,您永远不需要“告诉”编译器您要使用哪种 JSON 值类型。
如果您想明确或表达一些边缘情况,函数 json::array() 和 json::object() 将有所帮助:
1// a way to express the empty array []
2json empty_array_explicit = json::array();
3// ways to express the empty object {}
4json empty_object_implicit = json({});
5json empty_object_explicit = json::object();
6// a way to express an _array_ of key/value pairs [["currency", "USD"], ["value", 42.99]]
7json array_not_object = json::array({ {"currency", "USD"}, {"value", 42.99} });
3.3. 序列化json对象
您可以将json对象序列化为字符串,一般的常见std类型均可直接使用括号赋值,例如:
1std::vector<int> c_vector {1, 2, 3, 4};
2json j_vec(c_vector);
3// [1, 2, 3, 4]
4std::deque<double> c_deque {1.2, 2.3, 3.4, 5.6};
5json j_deque(c_deque);
6// [1.2, 2.3, 3.4, 5.6]
7std::list<bool> c_list {true, true, false, true};
8json j_list(c_list);
9// [true, true, false, true]
10std::forward_list<int64_t> c_flist {12345678909876, 23456789098765, 34567890987654, 45678909876543};
11json j_flist(c_flist);
12// [12345678909876, 23456789098765, 34567890987654, 45678909876543]
13std::array<unsigned long, 4> c_array {{1, 2, 3, 4}};
14json j_array(c_array);
15// [1, 2, 3, 4]
16std::set<std::string> c_set {"one", "two", "three", "four", "one"};
17json j_set(c_set); // only one entry for "one" is used
18// ["four", "one", "three", "two"]
19std::unordered_set<std::string> c_uset {"one", "two", "three", "four", "one"};
20json j_uset(c_uset); // only one entry for "one" is used
21// maybe ["two", "three", "four", "one"]
22std::multiset<std::string> c_mset {"one", "two", "one", "four"};
23json j_mset(c_mset); // both entries for "one" are used
24// maybe ["one", "two", "one", "four"]
25std::unordered_multiset<std::string> c_umset {"one", "two", "one", "four"};
26json j_umset(c_umset); // both entries for "one" are used
27// maybe ["one", "two", "one", "four"]
但是显然,我们还会需要自定义一些类型,比如:
1struct MyStruct {
2 int i;
3 std::string str;
4 bool b;
5};
这时候,你觉得应该怎么做?如果你觉得要这样:
1json j;
2MyStruct my_struct;
3j["i"] = my_struct.i;
4j["str"] = my_struct.str;
5j["b"] = my_struct.b;
6ofstream outputFile("data.json");
7outputFile << j.dump(4);
8outputFile.close();
那就有点脱裤子放屁了,失去了“序列化”的最重要意义——简洁表述。
官方给我们定义了一个宏 NLOHMANN_DEFINE_TYPE_INTRUSIVE(name, member1, member2, ...) ,用于自定义类型的序列化,我们可以这样使用:
1struct MyStruct {
2 int i;
3 std::string str;
4 bool b;
5 NLOHMANN_DEFINE_TYPE_INTRUSIVE(MyStruct, i, str, b)
6};
7json j;
8MyStruct my_struct;
9j = my_struct;
10ofstream outputFile("data.json");
11outputFile << j.dump(4);
12outputFile.close();
这样就可以自动序列化了,是不是很简洁?
3.4. 反序列化json对象
反序列化也是一样的,我们可以这样使用:
1json j = R"(
2{
3 "happy": true,
4 "pi": 3.141
5}
6)"_json;
7bool b = j.at("happy");
8double pi = j.at("pi");
对于自定义的类型,我们可以这样使用:
1struct MyStruct {
2 int i;
3 std::string str;
4 bool b;
5 NLOHMANN_DEFINE_TYPE_INTRUSIVE(MyStruct, i, str, b)
6};
7json j = R"(
8{
9 "i": 1,
10 "str": "hello",
11 "b": true
12}
13)"_json;
14MyStruct my_struct = j;