c++中nlohmann?json的基本使用教程
一.json.hpp庫下載及安裝
1.1 開源地址及引入方法
nlohmann json的開源項目地址,其中有對json使用方法的詳細(xì)說明:
https://github.com/nlohmann/json#serialization–deserialization
對于我們項目中要使用nlohmann json工具,只需要引入json.hpp這一個文件,其中包含所有接口函數(shù),正如其文檔中所述json.hpp文件在single_include/nlohmann目錄下,我們只需要下載該文件即可:
git clone https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp

如上圖片所示,使用json.hpp文件需要關(guān)注兩點:
一是:#include <nlohmann/json.hpp>頭文件路徑的引入,這里將json.hpp文件放到linux系統(tǒng)中的/usr/local/include路徑下,這是系統(tǒng)默認(rèn)頭文件路徑,在編譯時系統(tǒng)會自動查找該路徑。我們在/usr/local/include路徑下創(chuàng)建/nlohmann/json.hpp,如下圖所示:

二是:在編譯時需要指定c++11標(biāo)準(zhǔn),-std=c++11。
1.2 demo程序測試
jsontest.cpp:
#include <iostream>
#include <nlohmann/json.hpp> //引入json.hpp,該文件已經(jīng)放在系統(tǒng)默認(rèn)路徑:/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})"); //構(gòu)建json對象
cout << config_json << endl; //輸出json對象值
return 0;
}
編譯:
g++ jsontest.cpp -std=c++11
輸出結(jié)果:
{“happy”:true,“pi”:3.141}
二.nlohmann json基本操作
2.1 由basic value創(chuàng)建json
兩種方式創(chuàng)建json對象:賦值構(gòu)造+直接構(gòu)造
jsontest.cpp:
#include <iostream>
#include <nlohmann/json.hpp> //引入json.hpp,該文件已經(jīng)放在系統(tǒng)默認(rèn)路徑:/usr/local/include/nlohmann/json.hpp
using namespace std;
using json = nlohmann::json; // for convenience
int main()
{
//方式一:賦值構(gòu)造
json j1;
j1["name"]="LeBorn Jame";//字符串
j1["number"]=23; //整數(shù)
j1["man"]=true; //布爾值
j1["children"]={"LeBorn Jr","Bryce Maximus","Zhuri"};//數(shù)組
j1["behavior"]["funny"]="gigigigigigi"; //對象中元素值
j1["wife"]={{"name","Savannah Brinson"},{"man",false}};//對象
//方式二:直接構(gòu)造
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
輸出結(jié)果:
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
#include <iostream>
#include <string>
#include <nlohmann/json.hpp> //引入json.hpp,該文件已經(jīng)放在系統(tǒng)默認(rèn)路徑:/usr/local/include/nlohmann/json.hpp
using namespace std;
using json = nlohmann::json; // for convenience
int main()
{
//構(gòu)建一個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”對應(yīng)的value值,并轉(zhuǎn)為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;
}
輸出結(jié)果:
name = hututu
type name = Ss
location0 = aaa
location1 = bbb
location2 = ccc
2.3 像操作stl container一樣操作json value
#include <iostream>
#include <string>
#include <nlohmann/json.hpp> //引入json.hpp,該文件已經(jīng)放在系統(tǒng)默認(rèn)路徑:/usr/local/include/nlohmann/json.hpp
using namespace std;
using json = nlohmann::json; // for convenience
int main()
{
//構(gòu)建一個json對象animalArray
json animalArray={"cat","dog"};//定義一個數(shù)組類型的json對象
animalArray.push_back("pig");//添加元素
animalArray.emplace_back("duck");//C++11新方式添加元素,減少申請內(nèi)存
cout<<"animalArray: "<<animalArray<<endl;
//使用is_array()函數(shù)判斷對象類型,使用empty函數(shù)判斷數(shù)量是否為空
if(animalArray.is_array() && !animalArray.empty())
{
auto size=animalArray.size(); //使用size函數(shù)獲取元素數(shù)量
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函數(shù)判斷是否包含某個key
{
auto height=animalObject["height"].get<double>();
cout<<"方式一:height: "<<height<<endl;
}
//判斷是否含有某個鍵值方式二
auto size=animalObject.count("height");//通過count函數(shù)計算某一個鍵的數(shù)量
if(size>0)
{
cout<<"方式二:存在height鍵值"<<endl;
}
//判斷是否含有某個鍵值方式三
auto iter=animalObject.find("height");//通過find函數(shù)查找某個鍵的迭代器
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;
}
輸出結(jié)果:
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
#include <iostream>
#include <string>
#include <nlohmann/json.hpp> //引入json.hpp,該文件已經(jīng)放在系統(tǒng)默認(rèn)路徑:/usr/local/include/nlohmann/json.hpp
using namespace std;
using json = nlohmann::json; // for convenience
int main()
{
//反序列化構(gòu)建json對象,兩種方式
json hututu1 = "{\"name\":\"hututu\",\"age\":18,\"score\":88.99}"_json;//方式1,通過"_json"實現(xiàn)反序列化
auto temp = R"({"name":"hututu","age":18,"score":88.99})";//使用原生字符串關(guān)鍵字R來避免轉(zhuǎn)移字符,但這一句并沒有序列化,hututu2只保存字符串而已,需要結(jié)合方式3實現(xiàn)反序列化
json hututu2 = json::parse(temp);//方式2,通過靜態(tài)函數(shù)"parse"實現(xiàn)反序列化
cout<<"/----------反序列化-----------/"<<endl;
cout<<"hututu1 = "<<hututu1<<endl;
cout<<"hututu2 = "<<hututu2<<endl;
cout<<"/----------序列化-----------/"<<endl;
//序列化(Serialization):dump(number),number為打印出的空格數(shù)
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;
}
輸出結(jié)果:
/----------反序列化-----------/
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對象和文件輸入輸出轉(zhuǎn)換
#include <iostream> //文件操作頭文件
#include <string>
#include <fstream>
#include <nlohmann/json.hpp> //引入json.hpp,該文件已經(jīng)放在系統(tǒng)默認(rèn)路徑:/usr/local/include/nlohmann/json.hpp
using namespace std;
using json = nlohmann::json; // for convenience
int main()
{
//上述操作適用于istream和ostream的子類,比如我們經(jīng)常會用到的ifstream和ofstream
//從.json文件中讀取內(nèi)容到j(luò)son對象中
std::ifstream in("./person.json");//打開文件,關(guān)聯(lián)到流in
json hututu={"111","222"}; //定義一個json對象為hututu,有初始內(nèi)容,但是會被覆蓋
in>>hututu; //從流in中(也就是./person.json文件)讀取內(nèi)容到j(luò)son對象中,會覆蓋之前內(nèi)容
in.close(); //關(guān)閉文件流in
hututu["aaa"]="bbb"; //添加json對象內(nèi)容
cout << hututu << endl; //輸出json對象值
//輸出json對象內(nèi)容到文件中,并生成新的文件
std::ofstream out("./new.json"); //創(chuàng)建文件./new.json,并關(guān)聯(lián)到流out
hututu["name"]="new name"; //更改hututu對象的內(nèi)容
out<<std::setw(4)<<hututu; //輸出json對象hututu信息到文件./new.json中,std::setw(4)用于設(shè)置增加打印空格
out.close(); //關(guān)閉文件流out
return 0;
}
./person.json文件內(nèi)容
{
“name”:“hututu”,
“age”:18,
“gender”:“m”,
“score”:88.99
}
執(zhí)行程序后,輸出的json對象內(nèi)容如下,也就是從./person.json文件中讀取的信息:
{“aaa”:“bbb”,“age”:18,“gender”:“m”,“name”:“hututu”,“score”:88.99}
同時在當(dāng)前目錄下生成新的文件./new.json,內(nèi)容如下所示:
{
“aaa”: “bbb”,
“age”: 18,
“gender”: “m”,
“name”: “new name”,
“score”: 88.99
}
3.3 json value和自定義對象
在自定義對象命名空間中定義兩個函數(shù)即可像basic value一樣進(jìn)行反序列化和序列化:from_json(const json& j,T& value)、to_json(json& j,const T& value)
#include <iostream> //文件操作頭文件
#include <string>
#include <nlohmann/json.hpp> //引入json.hpp,該文件已經(jīng)放在系統(tǒng)默認(rèn)路徑:/usr/local/include/nlohmann/json.hpp
using namespace std;
using json = nlohmann::json;
class person
{
public:
person(){} //默認(rèn)構(gòu)造函數(shù)
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)函數(shù),用于序列化
//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)函數(shù),用于反序列化
//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隱式轉(zhuǎn)換-----------/"<<endl;
json j1=hututu; //class to json,隱式調(diào)用to_json函數(shù)
cout<<"j1 = "<<j1<<endl; //輸出json對象值
cout<<"/----------to json,方式2:調(diào)用to_json函數(shù)-----------/"<<endl;
json j2;
to_json(j2,hututu); //to json,調(diào)用to_json函數(shù)
cout<<"j2 = "<<j2<<endl; //輸出json對象值
cout<<"/----------from json,方式1:調(diào)用from_json函數(shù)-----------/"<<endl;
j1["name"]="new name"; //修改json對象數(shù)據(jù)
cout<<"new j1 = "<<j1<<endl; //輸出json對象值
person hututu_new;
from_json(j1,hututu_new); //json---->class
hututu_new.display(); //輸出person對象內(nèi)容
cout<<"/----------from json,方式2:調(diào)用.get函數(shù)-----------/"<<endl;
person hututuNew = j2.get<person>();//像basic value一樣通過get函數(shù)獲取值,將其值直接賦值給自定義對象
hututuNew.display();
return 0;
}
執(zhí)行結(jié)果:
/----------to json,方式1:json=class隱式轉(zhuǎn)換-----------/
j1 = {“age”:18,“name”:“hututu”,“score”:88.99}
/----------to json,方式2:調(diào)用to_json函數(shù)-----------/
j2 = {“age”:18,“name”:“hututu”,“score”:88.99}
/----------from json,方式1:調(diào)用from_json函數(shù)-----------/
new j1 = {“age”:18,“name”:“new name”,“score”:88.99}
person name = new name
person age = 18
person score = 88.99
/----------from json,方式2:調(diào)用.get函數(shù)-----------/
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, …) 將在要為其創(chuàng)建代碼的類/結(jié)構(gòu)的命名空間內(nèi)定義。
NLOHMANN_DEFINE_TYPE_INTRUSIVE(name, member1, member2, …) 將在要為其創(chuàng)建代碼的類/結(jié)構(gòu)中定義。 該宏還可以訪問私有成員。
進(jìn)一步查看代碼:
/*!
@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 宏的使用
可以看出上述的宏主要實現(xiàn)了from_json和to_json兩個函數(shù)的功能,使用時需要在一個類中調(diào)用該宏,并傳入(類名,參數(shù)1,參數(shù)2,參數(shù)3…)使用,這樣在json對象和class對象之間之間直接賦值可以完成相互轉(zhuǎn)換,具體用法如下:
#include <iostream> //文件操作頭文件
#include <string>
#include <nlohmann/json.hpp> //引入json.hpp,該文件已經(jīng)放在系統(tǒng)默認(rèn)路徑:/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<<"/----------調(diào)用宏實現(xiàn):to json-----------/"<<endl;
json j1 = hututu;
cout << j1<< endl;
cout << j1.dump() << endl;
cout<<"/----------調(diào)用宏實現(xiàn):from json-----------/"<<endl;
j1["name"]="new name";
person hututu_new = j1;
hututu_new.display();
return 0;
}
輸出結(jié)果:
/----------調(diào)用宏實現(xiàn):to json-----------/
{“age”:18,“name”:“hututu”,“score”:88.99}
{“age”:18,“name”:“hututu”,“score”:88.99}
/----------調(diào)用宏實現(xiàn):from json-----------/
person name = new name
person age = 18
person score = 88.99
總結(jié)
到此這篇關(guān)于c++中nlohmann json基本使用的文章就介紹到這了,更多相關(guān)c++ nlohmann json使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
VS2019創(chuàng)建C++工程的的實現(xiàn)步驟
本文主要介紹了VS2019創(chuàng)建C++工程步驟,包含新建項目、編輯文件、配置源文件目錄、編譯鏈接、輸出文件、設(shè)置斷點調(diào)試,具有一定的參考價值,感興趣的可以了解一下2024-12-12
vector與map的erase()函數(shù)詳細(xì)解析
vector和map都不能將it++寫在for循環(huán)中,而在循環(huán)體內(nèi)erase(it)2013-09-09
C語言實例真題講解數(shù)據(jù)結(jié)構(gòu)中單向環(huán)形鏈表
鏈表可以說是一種最為基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu)了,而單向鏈表更是基礎(chǔ)中的基礎(chǔ)。鏈表是由一組元素以特定的順序組合或鏈接在一起的,不同元素之間在邏輯上相鄰,但是在物理上并不一定相鄰。在維護(hù)一組數(shù)據(jù)集合時,就可以使用鏈表,這一點和數(shù)組很相似2022-04-04

