nlohmann/json 是一个C++实现的JSON解析器,使用非常方便直观,下面这篇文章主要给大家介绍了关于c++中nlohmann json基本使用的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下

一.json.hpp库下载及安装

1.1 开源地址及引入方法

nlohmann json的开源项目地址,其中有对json使用方法的详细说明:

https://github.com/nlohmann/json#serialization–deserialization

对于我们项目中要使用nlohmann json工具,只需要引入json.hpp这一个文件,其中包含所有接口函数,正如其文档中所述json.hpp文件在single_include/nlohmann目录下,我们只需要下载该文件即可:

git clone https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp

如上图片所示,使用json.hpp文件需要关注两点:

一是:#include <nlohmann/json.hpp>头文件路径的引入,这里将json.hpp文件放到linux系统中的/usr/local/include路径下,这是系统默认头文件路径,在编译时系统会自动查找该路径。我们在/usr/local/include路径下创建/nlohmann/json.hpp,如下图所示:

二是:在编译时需要指定c++11标准,-std=c++11。

1.2 demo程序测试

jsontest.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
#include <nlohmann/json.hpp>   //引入json.hpp,该文件已经放在系统默认路径:/usr/local/include/nlohmann/json.hpp
using namespace std;
// for convenience
using json = nlohmann::json;
int main()
{
   auto config_json = json::parse(R "({" happy ": true, " pi ": 3.141})" );  //构建json对象
   cout << config_json << endl;   //输出json对象值
   return 0;
}

编译:

g++ jsontest.cpp -std=c++11

输出结果:

{“happy”:true,“pi”:3.141}

二.nlohmann json基本操作

2.1 由basic value创建json

两种方式创建json对象:赋值构造+直接构造

jsontest.cpp:

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
#include <iostream>
#include <nlohmann/json.hpp>   //引入json.hpp,该文件已经放在系统默认路径:/usr/local/include/nlohmann/json.hpp
using namespace std;
using json = nlohmann::json;    // for convenience
int main()
{
   //方式一:赋值构造
   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 }}}
   };
   cout << "j1: " <<j1 << endl;   //输出json对象值
   cout <<  "j2: " <<j2 << endl;   //输出json对象值
   return 0;
}

编译:

g++ jsontest.cpp -std=c++11

输出结果:

j1: {“behavior”:{“funny”:“gigigigigigi”},“children”:[“LeBorn Jr”,“Bryce Maximus”,“Zhuri”],“man”:true,“name”:“LeBorn Jame”,“number”:23,“wife”:{“man”:false,“name”:“Savannah Brinson”}}
j2: {“behavior”:{“funny”:“gigigigigigi”},“children”:[“LeBorn Jr”,“Bryce Maximus”,“Zhuri”],“man”:true,“name”:“LeBorn Jame”,“number”:23,“wife”:{“man”:false,“name”:“Savannah Brinson”}}

2.2 由json对象得到basic value

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
32
33
#include <iostream>
#include <string>
#include <nlohmann/json.hpp>   //引入json.hpp,该文件已经放在系统默认路径:/usr/local/include/nlohmann/json.hpp
using namespace std;
using json = nlohmann::json;    // for convenience
int main()
{
   //构建一个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类型
   cout<< "name = " <<name<<endl;
   cout<< "type name = " << typeid (name).name()<<endl;
   cout<< "----------------------" <<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>();
   cout<< "location0 = " <<location0<<endl;
   cout<< "location1 = " <<location1<<endl;
   cout<< "location2 = " <<location2<<endl;
   return 0;
}

输出结果:

name = hututu
type name = Ss
location0 = aaa
location1 = bbb
location2 = ccc

2.3 像操作stl container一样操作json value

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <iostream>
#include <string>
#include <nlohmann/json.hpp>   //引入json.hpp,该文件已经放在系统默认路径:/usr/local/include/nlohmann/json.hpp
using namespace std;
using json = nlohmann::json;    // for convenience
int main()
{
   //构建一个json对象animalArray
   json animalArray={ "cat" , "dog" }; //定义一个数组类型的json对象
   animalArray.push_back( "pig" ); //添加元素
   animalArray.emplace_back( "duck" ); //C++11新方式添加元素,减少申请内存
   cout<< "animalArray: " <<animalArray<<endl;
   //使用is_array()函数判断对象类型,使用empty函数判断数量是否为空
   if (animalArray.is_array() && !animalArray.empty())
   {
       auto size=animalArray.size();          //使用size函数获取元素数量
       cout<< "animalArray size: " <<size<<endl;
       auto animalLast=animalArray.at(size-1).get<std::string>();
       cout<< "animalArray[size-1]: " <<animalLast<<endl;
       cout<< "/--------------------/" <<endl;
   }
   json animalObject={{ "kind" , "dog" },{ "height" ,50}}; //定义一个对象类型的json对象
   animalObject.push_back({ "color" , "red" }); //插入元素
   animalObject.erase( "kind" ); //删除键值
   cout<< "animalObject: " <<animalObject<<endl;
   animalObject[ "height" ] = 99;   //通过key修改value值
   //判断是否含有某个键值方式一
   if (animalObject.contains( "height" )) //通过contains函数判断是否包含某个key
   {
       auto height=animalObject[ "height" ].get< double >();
       cout<< "方式一:height: " <<height<<endl;
   }
   //判断是否含有某个键值方式二
   auto size=animalObject.count( "height" ); //通过count函数计算某一个键的数量
   if (size>0)
   {
       cout<< "方式二:存在height键值" <<endl;
   }
   //判断是否含有某个键值方式三
   auto iter=animalObject.find( "height" ); //通过find函数查找某个键的迭代器
   if (iter!=animalObject.end())
   {
       cout<< "方式三:存在height键值" <<endl;
   }
   //遍历输出键值方式1
   cout<< "遍历输出键值方式1:" <<endl;
   for (auto item:animalObject.items())
   {
       std::cout<<item.key()<< " " <<item.value()<<std::endl;
   }
   //遍历输出键值方式2
   cout<< "遍历输出键值方式2:" <<endl;
   for (auto iter=animalObject.begin();iter!=animalObject.end();++iter)
   {
       cout<<iter.key()<< " " <<iter.value()<<std::endl;
   }
   return 0;
}

输出结果:

animalArray: [“cat”,“dog”,“pig”,“duck”]
animalArray size: 4
animalArray[size-1]: duck
/--------------------/
animalObject: {“color”:“red”,“height”:50}
方式一:height: 99
方式二:存在height键值
方式三:存在height键值
遍历输出键值方式1:
color “red”
height 99
遍历输出键值方式2:
color “red”
height 99

三.json序列化与反序列化

3.1 json value和string

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
#include <iostream>
#include <string>
#include <nlohmann/json.hpp>   //引入json.hpp,该文件已经放在系统默认路径:/usr/local/include/nlohmann/json.hpp
using namespace std;
using json = nlohmann::json;    // for convenience
int main()
{
   //反序列化构建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"实现反序列化
   cout<< "/----------反序列化-----------/" <<endl;
   cout<< "hututu1 = " <<hututu1<<endl;
   cout<< "hututu2 = " <<hututu2<<endl;
   cout<< "/----------序列化-----------/" <<endl;
   //序列化(Serialization):dump(number),number为打印出的空格数
   std::string hututu1_string=hututu1.dump(); //animal1值为{"kind":"dog","height":50}
   std::string hututu2_string=hututu2.dump(4);
   cout<< "hututu1_string = " <<hututu1_string<<endl;
   cout<< "hututu2_string = " <<hututu2_string<<endl;
   return 0;
}

输出结果:

/----------反序列化-----------/
hututu1 = {“age”:18,“name”:“hututu”,“score”:88.99}
hututu2 = {“age”:18,“name”:“hututu”,“score”:88.99}
/----------序列化-----------/
hututu1_string = {“age”:18,“name”:“hututu”,“score”:88.99}
hututu2_string = {
“age”: 18,
“name”: “hututu”,
“score”: 88.99
}

3.2 json对象和文件输入输出转换

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
#include <iostream>        //文件操作头文件
#include <string>
#include <fstream>
#include <nlohmann/json.hpp>   //引入json.hpp,该文件已经放在系统默认路径:/usr/local/include/nlohmann/json.hpp
using namespace std;
using json = nlohmann::json;    // for convenience
int main()
{
   //上述操作适用于istream和ostream的子类,比如我们经常会用到的ifstream和ofstream
   //从.json文件中读取内容到json对象中
   std::ifstream in( "./person.json" ); //打开文件,关联到流in
   json hututu={ "111" , "222" };      //定义一个json对象为hututu,有初始内容,但是会被覆盖
   in>>hututu;                     //从流in中(也就是./person.json文件)读取内容到json对象中,会覆盖之前内容
   in.close();                     //关闭文件流in
   hututu[ "aaa" ]= "bbb" ;             //添加json对象内容
   cout << hututu << endl;   //输出json对象值
   //输出json对象内容到文件中,并生成新的文件
   std::ofstream out( "./new.json" );    //创建文件./new.json,并关联到流out
   hututu[ "name" ]= "new name" ;          //更改hututu对象的内容
   out<<std::setw(4)<<hututu;          //输出json对象hututu信息到文件./new.json中,std::setw(4)用于设置增加打印空格
   out.close();         //关闭文件流out
   return 0;
}

./person.json文件内容

{
“name”:“hututu”,
“age”:18,
“gender”:“m”,
“score”:88.99
}

执行程序后,输出的json对象内容如下,也就是从./person.json文件中读取的信息:

{“aaa”:“bbb”,“age”:18,“gender”:“m”,“name”:“hututu”,“score”:88.99}

同时在当前目录下生成新的文件./new.json,内容如下所示:

{
“aaa”: “bbb”,
“age”: 18,
“gender”: “m”,
“name”: “new name”,
“score”: 88.99
}

3.3 json value和自定义对象

在自定义对象命名空间中定义两个函数即可像basic value一样进行反序列化和序列化:from_json(const json& j,T& value)、to_json(json& j,const T& value)

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <iostream>        //文件操作头文件
#include <string>
#include <nlohmann/json.hpp>   //引入json.hpp,该文件已经放在系统默认路径:/usr/local/include/nlohmann/json.hpp
using namespace std;
using json = nlohmann::json;
class person
{
     public :
         person(){}       //默认构造函数
         person(string m_name, int m_age, double m_score):name(m_name),age(m_age),score(m_score){};
     public :
       string name;
       int age;
       double score;
     void display()
     {
       cout<< "person name = " << this ->name<<endl;
       cout<< "person age = " << this ->age<<endl;
       cout<< "person score = " << this ->score<<endl;
     }
};
//定义from_json(const json& j,T& value)函数,用于序列化
//json对象----->class对象
void from_json( const json& j,person& hututu)
{
     hututu.name=j[ "name" ].get<std::string>();
     hututu.age=j[ "age" ].get< int >();
     hututu.score=j[ "score" ].get< double >();
}
//定义to_json(json& j,const T& value)函数,用于反序列化
//class对象----->json对象
void to_json(json& j, const person& hututu)
{
     j[ "name" ]=hututu.name;
     j[ "age" ]=hututu.age;
     j[ "score" ]=hututu.score;
}
// 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);
// }
//main.cpp文件
int main()
{
     person hututu{ "hututu" ,18,88.99}; //定义一个person对象为hututu
     cout<< "/----------to json,方式1:json=class隐式转换-----------/" <<endl;
     json j1=hututu;                //class to json,隐式调用to_json函数
     cout<< "j1 = " <<j1<<endl;       //输出json对象值
     cout<< "/----------to json,方式2:调用to_json函数-----------/" <<endl;
     json j2;
     to_json(j2,hututu);          //to json,调用to_json函数
     cout<< "j2 = " <<j2<<endl;     //输出json对象值
     cout<< "/----------from json,方式1:调用from_json函数-----------/" <<endl;
     j1[ "name" ]= "new name" ;        //修改json对象数据
     cout<< "new j1 = " <<j1<<endl;        //输出json对象值
     person hututu_new;
     from_json(j1,hututu_new);   //json---->class
     hututu_new.display();     //输出person对象内容
     cout<< "/----------from json,方式2:调用.get函数-----------/" <<endl;
     person hututuNew = j2.get<person>(); //像basic value一样通过get函数获取值,将其值直接赋值给自定义对象
     hututuNew.display();
     return 0;
}

执行结果:

/----------to json,方式1:json=class隐式转换-----------/
j1 = {“age”:18,“name”:“hututu”,“score”:88.99}
/----------to json,方式2:调用to_json函数-----------/
j2 = {“age”:18,“name”:“hututu”,“score”:88.99}
/----------from json,方式1:调用from_json函数-----------/
new j1 = {“age”:18,“name”:“new name”,“score”:88.99}
person name = new name
person age = 18
person score = 88.99
/----------from json,方式2:调用.get函数-----------/
person name = hututu
person age = 18
person score = 88.99

四.NLOHMANN_DEFINE_TYPE_INTRUSIVE宏的使用

4.1 宏的定义

JSON for Modern C++ 中为方便序列化和反序列化定义了两宏,如下

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(name, member1, member2, …) 将在要为其创建代码的类/结构的命名空间内定义。
NLOHMANN_DEFINE_TYPE_INTRUSIVE(name, member1, member2, …) 将在要为其创建代码的类/结构中定义。 该宏还可以访问私有成员。

进一步查看代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*!
@brief macro
@def NLOHMANN_DEFINE_TYPE_INTRUSIVE
@since version 3.9.0
*/
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...)  \
     friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
     friend void from_json( const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
/*!
@brief macro
@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE
@since version 3.9.0
*/
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...)  \
     inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
     inline void from_json( const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }

4.2 宏的使用

可以看出上述的宏主要实现了from_json和to_json两个函数的功能,使用时需要在一个类中调用该宏,并传入(类名,参数1,参数2,参数3…)使用,这样在json对象和class对象之间之间直接赋值可以完成相互转换,具体用法如下:

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
32
33
34
35
36
37
38
39
#include <iostream>        //文件操作头文件
#include <string>
#include <nlohmann/json.hpp>   //引入json.hpp,该文件已经放在系统默认路径:/usr/local/include/nlohmann/json.hpp
using namespace std;
using json = nlohmann::json;
class person
{
    public :
       string name;
       int age;
       double score;
       void display()
       {
         cout<< "person name = " << this ->name<<endl;
         cout<< "person age = " << this ->age<<endl;
         cout<< "person score = " << this ->score<<endl;
       }
       // 类名,成员1,成员2,成员3
       NLOHMANN_DEFINE_TYPE_INTRUSIVE(person, name, age, score);
};
//main.cpp文件
int main()
{
     person hututu{ "hututu" ,18,88.99}; //定义一个person对象为hututu
     cout<< "/----------调用宏实现:to json-----------/" <<endl;
     json j1 = hututu;
     cout << j1<< endl;
     cout << j1.dump() << endl;
     cout<< "/----------调用宏实现:from json-----------/" <<endl;
     j1[ "name" ]= "new name" ;
     person hututu_new = j1;
     hututu_new.display();
     return 0;
}

输出结果:

/----------调用宏实现:to json-----------/
{“age”:18,“name”:“hututu”,“score”:88.99}
{“age”:18,“name”:“hututu”,“score”:88.99}
/----------调用宏实现:from json-----------/
person name = new name
person age = 18
person score = 88.99

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐