nlohmann/json是一个C++的JSON解析库,由nlohmann开发。
它支持C++11及更高版本,并且可以在多个平台上使用,包括Windows、Linux和macOS等。
nlohmann/json提供了一组简单易用的API,可以方便地将JSON数据转换为C++对象,也可以将C++对象序列化为JSON格式。
nlohmann/json的主要特点包括:
轻量级:只包含头文件,不需要链接额外的库文件。
简单易用:提供了类似于STL容器的API,可以方便地处理JSON数据。
高效性能:使用了现代C++的特性,如移动语义和模板元编程等,可以获得高效的性能。
兼容性强:支持多种JSON格式,包括RFC 8259、ECMA-404和JSON5等。
开源免费:nlohmann/json是开源的,使用MIT许可证,可以免费使用和修改。
nlohmann/json已经成为C++领域中最流行的JSON解析库之一,被广泛应用于各种C++项目中,包括游戏开发、Web应用开发、物联网等领域。
开源地址
对于我们使用者来说,只需要引入json.hpp这一个文件,其中包含所有接口函数。
json.hpp文件在single_include/nlohmann目录下,我们只需要下载该文件即可
#include
#include
// #include
#include
#include "nlohmann/json.hpp"
using json = nlohmann::json;
void test0()
{
auto config_json = json::parse(R"({"happy": true, "pi": 3.141})"); // 构建json对象
std::cout << config_json << std::endl; // 输出json对象值
return;
}
void test1()
{
// 方式一:赋值构造
json j1;
j1["name"] = "LeBorn Jame"; // 字符串
j1["number"] = 23; // 整数
j1["man"] = true; // 布尔值
j1["children"] = {"LeBorn Jr", "Bryce Maximus", "Zhuri"}; // 数组
j1["behavior"]["funny"] = "gigigigigigi"; // 对象中元素值
j1["wife"] = {{"name", "Savannah Brinson"}, {"man", false}}; // 对象
// 方式二:直接构造
json j2 = {
{"name", "LeBorn Jame"},
{"number", 23},
{"man", true},
{"children", {"LeBorn Jr", "Bryce Maximus", "Zhuri"}},
{"behavior", {{"funny", "gigigigigigi"}}},
{"wife", {{"name", "Savannah Brinson"}, {"man", false}}}
};
std::cout << "j1: " << j1 << std::endl;
std::cout << "j2: " << j2 << std::endl;
return;
}
void test2()
{
// 构建一个json对象hututu
json hututu = {
{"name", "hututu"},
{"age", 18},
{"gender", 'm'},
{"score", 88.99},
{"location", {"aaa", "bbb", "ccc"}},
};
// 方式一
auto name = hututu["name"].get<std::string>(); // 获取“name”对应的value值,并转为string类型
std::cout << "name = " << name << std::endl;
std::cout << "type name = " << typeid(name).name() << std::endl;
std::cout << "----------------------" << std::endl;
// 方式二
auto location0 = hututu["location"][0].get<std::string>();
auto location1 = hututu["location"][1].get<std::string>();
auto location2 = hututu["location"].at(2).get<std::string>();
std::cout << "location0 = " << location0 << std::endl;
std::cout << "location1 = " << location1 << std::endl;
std::cout << "location2 = " << location2 << std::endl;
return;
}
void test3()
{
// 构建一个json对象animalArray
json animalArray = {"cat", "dog"}; // 定义一个数组类型的json对象
animalArray.push_back("pig"); // 添加元素
animalArray.emplace_back("duck"); // C++11新方式添加元素,减少申请内存
std::cout << "animalArray: " << animalArray << std::endl;
// 使用is_array()函数判断对象类型,使用empty函数判断数量是否为空
if (animalArray.is_array() && !animalArray.empty())
{
auto size = animalArray.size(); // 使用size函数获取元素数量
std::cout << "animalArray size: " << size << std::endl;
auto animalLast = animalArray.at(size - 1).get<std::string>();
std::cout << "animalArray[size-1]: " << animalLast << std::endl;
std::cout << "/--------------------/" << std::endl;
}
json animalObject = {{"kind", "dog"}, {"height", 50}}; // 定义一个对象类型的json对象
animalObject.push_back({"color", "red"}); // 插入元素
animalObject.erase("kind"); // 删除键值
std::cout << "animalObject: " << animalObject << std::endl;
animalObject["height"] = 99; // 通过key修改value值
// 判断是否含有某个键值方式一
if (animalObject.contains("height")) // 通过contains函数判断是否包含某个key
{
auto height = animalObject["height"].get<double>();
std::cout << "方式一:height: " << height << std::endl;
}
// 判断是否含有某个键值方式二
auto size = animalObject.count("height"); // 通过count函数计算某一个键的数量
if (size > 0)
{
std::cout << "方式二:存在height键值" << std::endl;
}
// 判断是否含有某个键值方式三
auto iter = animalObject.find("height"); // 通过find函数查找某个键的迭代器
if (iter != animalObject.end())
{
std::cout << "方式三:存在height键值" << std::endl;
}
// 遍历输出键值方式1
std::cout << "遍历输出键值方式1:" << std::endl;
for (auto item : animalObject.items())
{
std::cout << item.key() << " " << item.value() << std::endl;
}
// 遍历输出键值方式2
std::cout << "遍历输出键值方式2:" << std::endl;
for (auto iter = animalObject.begin(); iter != animalObject.end(); ++iter)
{
std::cout << iter.key() << " " << iter.value() << std::endl;
}
return;
}
void test4(){
// 反序列化构建json对象,两种方式
json hututu1 = "{\"name\":\"hututu\",\"age\":18,\"score\":88.99}"_json; // 方式1,通过"_json"实现反序列化
auto temp = R"({"name":"hututu","age":18,"score":88.99})"; // 使用原生字符串关键字R来避免转移字符,但这一句并没有序列化,hututu2只保存字符串而已,需要结合方式3实现反序列化
json hututu2 = json::parse(temp); // 方式2,通过静态函数"parse"实现反序列化
std::cout << "/----------反序列化-----------/" << std::endl;
std::cout << "hututu1 = " << hututu1 << std::endl;
std::cout << "hututu2 = " << hututu2 << std::endl;
std::cout << "/----------序列化-----------/" << std::endl;
// 序列化(Serialization):dump(number),number为打印出的空格数
std::string hututu1_string = hututu1.dump(); // animal1值为{"kind":"dog","height":50}
std::string hututu2_string = hututu2.dump(4);
std::cout << "hututu1_string = " << hututu1_string << std::endl;
std::cout << "hututu2_string = " << hututu2_string << std::endl;
return;
}
void test5(std::string input,std::string output){
// 从.json文件中读取内容到json对象中
std::ifstream in(input); // 打开文件,关联到流in
json hututu = {"111", "222"}; // 定义一个json对象为hututu,有初始内容,但是会被覆盖
in >> hututu; // 从流in中(也就是./person.json文件)读取内容到json对象中,会覆盖之前内容
in.close(); // 关闭文件流in
hututu["aaa"] = "bbb"; // 添加json对象内容
std::cout << hututu << std::endl; // 输出json对象值
// 输出json对象内容到文件中,并生成新的文件
std::ofstream out(output); // 创建文件./new.json,并关联到流out
hututu["name"] = "new name"; // 更改hututu对象的内容
out << std::setw(4) << hututu; // 输出json对象hututu信息到文件./new.json中,std::setw(4)用于设置增加打印空格
out.close(); // 关闭文件流out
return;
}
class Persion
{
public:
Persion()=default;
Persion(std::string n,int a,double s):name(n),age(a),score(s){};
void display()
{
std::cout << "person name = " << this->name << std::endl;
std::cout << "person age = " << this->age << std::endl;
std::cout << "person score = " << this->score << std::endl;
}
// 类名,成员1,成员2,成员3
NLOHMANN_DEFINE_TYPE_INTRUSIVE(Persion, name, age, score);
private:
std::string name;
int age;
double score;
};
void test6(){
Persion hututu{"hututu", 18, 88.99}; // 定义一个person对象为hututu
std::cout << "/----------调用宏实现:to json-----------/" << std::endl;
json j1 = hututu;
std::cout << j1 << std::endl;
std::cout << j1.dump() << std::endl;
std::cout << "/----------调用宏实现:from json-----------/" << std::endl;
j1["name"] = "new name";
Persion hututu_new = j1;
hututu_new.display();
return;
}
void call_func(const std::function<void(void)> &f) { f(); }
void call_func1(std::string a, std::string b, const std::function<void(std::string, std::string)> &f) { f(a, b); }
DEFINE_int32(testfucnum, 0, "测试哪个test");
DEFINE_string(input,"./input.json","测试读取的json文件");
DEFINE_string(output,"./output.json","测试生成的json文件");
int main(int argc, char **argv)
{
// Parsing command-line
google::ParseCommandLineFlags(&argc, &argv, true);
switch (FLAGS_testfucnum)
{
case 0:
call_func(test0);
break;
case 1: //两种方式创建json对象:赋值构造+直接构造
call_func(test1);
break;
case 2: //由json对象得到basic value
call_func(test2);
break;
case 3: //像操作stl container一样操作json value
call_func(test3);
break;
case 4: //json序列化与反序列化
call_func(test4);
break;
case 5: //json对象和文件输入输出转换
call_func1(FLAGS_input,FLAGS_output,test5);
break;
case 6: //NLOHMANN_DEFINE_TYPE_INTRUSIVE宏的使用
call_func(test6);
break;
default:
break;
}
return 0;
}