前言
C++ nlohmann/json 库是一个非常易用,高性能的 json 库。
CMake FetchContent方式集成
1
2
3
4
5
6
| include(FetchContent)
FetchContent_Declare(json
URL https://github.com/nlohmann/json/releases/download/v3.11.3/json.tar.xz)
FetchContent_MakeAvailable(json)
target_link_libraries(json_demo PRIVATE nlohmann_json::nlohmann_json)
|
快速使用
包含头文件以及声明命名空间别名:
1
2
| #include <nlohmann/json.hpp>
using json = nlohmann::json;
|
解析json
从文件读取解析
1
2
3
4
5
6
7
8
| // method 1
std::ifstream f("example.json");
json data = json::parse(f);
// method 2
std::ifstream i("file.json");
json j;
i >> j;
|
从字符串读取解析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| // Using (raw) string literals and json::parse
json ex1 = json::parse(R"(
{
"pi": 3.141,
"happy": true
}
)");
// Using user-defined (raw) string literals
using namespace nlohmann::literals;
json ex2 = R"(
{
"pi": 3.141,
"happy": true
}
)"_json;
// Using initializer lists
json ex3 = {
{"happy", true},
{"pi", 3.141},
};
|
遍历
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| // special iterator member functions for objects
for (json::iterator it = o.begin(); it != o.end(); ++it) {
std::cout << it.key() << " : " << it.value() << "\n";
}
// the same code as range for
for (auto& el : o.items()) {
std::cout << el.key() << " : " << el.value() << "\n";
}
// even easier with structured bindings (C++17)
for (auto& [key, value] : o.items()) {
std::cout << key << " : " << value << "\n";
}
|
查找 Key
1
2
3
4
5
| if (j.contains("key")) {
}
if (j.find("foo") != o.end()) {
}
|
读取 key
1
2
3
4
5
6
7
8
| auto value = j["key"];
auto value = j.at("key");
std::string value = j["key"].template get<std::string>();
// C++17
using namespace std::literals;
// 如果key不存在,则返回默认值0
int v_integer = j.value("integer"sv, 0);
|
删除 key
1
2
| // delete an entry
o.erase("foo");
|
注意:数组可能无法删除单个元素
写入 json 文件
1
2
| std::ofstream o("pretty.json");
o << std::setw(4) << j << std::endl;
|
序列化设置缩进
1
2
| // 按照四个空格缩进打印json
std::cout << j.dump(4) << std::endl;
|
任意类型转换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
| using json = nlohmann::json;
namespace ns {
struct person {
std::string name;
std::string address;
int age;
};
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);
}
} // namespace ns
// create a person
ns::person p {"Ned Flanders", "744 Evergreen Terrace", 60};
// conversion: person -> json
json j = p;
std::cout << j << std::endl;
// {"address":"744 Evergreen Terrace","age":60,"name":"Ned Flanders"}
// conversion: json -> person
auto p2 = j.template get<ns::person>();
|
通过实现to_json()
和from_json()
完成 json 与结构体的映射关系。
[!warning]
- 使用
template get<your_type>()
时,必须保证是可以默认构造的。 from_json
中,使用 at()
来访问对象的值,而不是 operator[]
。如果某个键不存在, at
会抛出一个可以处理的异常,而 operator[]
则会表现出未定义的行为。
如果想要将 JSON 对象用作序列化或想要将成员变量名称用作该对象的键。可以使用宏简化操作(自动实现to_json()
和from_json()
):
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(name, member1, member2, ...)
:在类/结构体的命名空间内进行定义。NLOHMANN_DEFINE_TYPE_INTRUSIVE(name, member1, member2, ...)
:在类/结构内部定义的标识符,用于创建代码。这个宏还可以访问私有成员。
命名空间中使用:
1
2
3
4
5
6
7
8
| namespace ns {
struct person {
std::string name;
std::string address;
int age;
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person, name, address, age)
}
|
使用私有成员:
1
2
3
4
5
6
7
8
9
10
11
| namespace ns {
class address {
private:
std::string street;
int housenumber;
int postcode;
public:
NLOHMANN_DEFINE_TYPE_INTRUSIVE(address, street, housenumber, postcode)
};
}
|
总结
以上就是在使用 json 库时的常用场景。
https://github.com/nlohmann/json
https://github.com/nlohmann/json/tree/develop/docs/examples