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

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

二是:在編譯時(shí)需要指定c++11標(biāo)準(zhǔn),-std=c++11。
1.2 demo程序測(cè)試
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對(duì)象
cout << config_json << endl; //輸出json對(duì)象值
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對(duì)象:賦值構(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"; //對(duì)象中元素值
j1["wife"]={{"name","Savannah Brinson"},{"man",false}};//對(duì)象
//方式二:直接構(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對(duì)象值
cout << "j2: "<<j2 << endl; //輸出json對(duì)象值
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對(duì)象得到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)建一個(gè)json對(duì)象hututu
json hututu = {
{"name","hututu"},
{"age",18},
{"gender",'m'},
{"score",88.99},
{"location",{"aaa","bbb","ccc"}},
};
//方式一
auto name = hututu["name"].get<std::string>(); //獲取“name”對(duì)應(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)建一個(gè)json對(duì)象animalArray
json animalArray={"cat","dog"};//定義一個(gè)數(shù)組類型的json對(duì)象
animalArray.push_back("pig");//添加元素
animalArray.emplace_back("duck");//C++11新方式添加元素,減少申請(qǐng)內(nèi)存
cout<<"animalArray: "<<animalArray<<endl;
//使用is_array()函數(shù)判斷對(duì)象類型,使用empty函數(shù)判斷數(shù)量是否為空
if(animalArray.is_array() && !animalArray.empty())
{
auto size=animalArray.size(); //使用size函數(shù)獲取元素?cái)?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}};//定義一個(gè)對(duì)象類型的json對(duì)象
animalObject.push_back({"color","red"});//插入元素
animalObject.erase("kind");//刪除鍵值
cout<<"animalObject: "<<animalObject<<endl;
animalObject["height"] = 99; //通過key修改value值
//判斷是否含有某個(gè)鍵值方式一
if(animalObject.contains("height"))//通過contains函數(shù)判斷是否包含某個(gè)key
{
auto height=animalObject["height"].get<double>();
cout<<"方式一:height: "<<height<<endl;
}
//判斷是否含有某個(gè)鍵值方式二
auto size=animalObject.count("height");//通過count函數(shù)計(jì)算某一個(gè)鍵的數(shù)量
if(size>0)
{
cout<<"方式二:存在height鍵值"<<endl;
}
//判斷是否含有某個(gè)鍵值方式三
auto iter=animalObject.find("height");//通過find函數(shù)查找某個(gè)鍵的迭代器
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對(duì)象,兩種方式
json hututu1 = "{\"name\":\"hututu\",\"age\":18,\"score\":88.99}"_json;//方式1,通過"_json"實(shí)現(xiàn)反序列化
auto temp = R"({"name":"hututu","age":18,"score":88.99})";//使用原生字符串關(guān)鍵字R來避免轉(zhuǎn)移字符,但這一句并沒有序列化,hututu2只保存字符串而已,需要結(jié)合方式3實(shí)現(xiàn)反序列化
json hututu2 = json::parse(temp);//方式2,通過靜態(tài)函數(shù)"parse"實(shí)現(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對(duì)象和文件輸入輸出轉(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)常會(huì)用到的ifstream和ofstream
//從.json文件中讀取內(nèi)容到j(luò)son對(duì)象中
std::ifstream in("./person.json");//打開文件,關(guān)聯(lián)到流in
json hututu={"111","222"}; //定義一個(gè)json對(duì)象為hututu,有初始內(nèi)容,但是會(huì)被覆蓋
in>>hututu; //從流in中(也就是./person.json文件)讀取內(nèi)容到j(luò)son對(duì)象中,會(huì)覆蓋之前內(nèi)容
in.close(); //關(guān)閉文件流in
hututu["aaa"]="bbb"; //添加json對(duì)象內(nèi)容
cout << hututu << endl; //輸出json對(duì)象值
//輸出json對(duì)象內(nèi)容到文件中,并生成新的文件
std::ofstream out("./new.json"); //創(chuàng)建文件./new.json,并關(guān)聯(lián)到流out
hututu["name"]="new name"; //更改hututu對(duì)象的內(nèi)容
out<<std::setw(4)<<hututu; //輸出json對(duì)象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對(duì)象內(nèi)容如下,也就是從./person.json文件中讀取的信息:
{“aaa”:“bbb”,“age”:18,“gender”:“m”,“name”:“hututu”,“score”:88.99}
同時(shí)在當(dāng)前目錄下生成新的文件./new.json,內(nèi)容如下所示:
{
“aaa”: “bbb”,
“age”: 18,
“gender”: “m”,
“name”: “new name”,
“score”: 88.99
}
3.3 json value和自定義對(duì)象
在自定義對(duì)象命名空間中定義兩個(gè)函數(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對(duì)象----->class對(duì)象
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對(duì)象----->json對(duì)象
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};//定義一個(gè)person對(duì)象為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對(duì)象值
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對(duì)象值
cout<<"/----------from json,方式1:調(diào)用from_json函數(shù)-----------/"<<endl;
j1["name"]="new name"; //修改json對(duì)象數(shù)據(jù)
cout<<"new j1 = "<<j1<<endl; //輸出json對(duì)象值
person hututu_new;
from_json(j1,hututu_new); //json---->class
hututu_new.display(); //輸出person對(duì)象內(nèi)容
cout<<"/----------from json,方式2:調(diào)用.get函數(shù)-----------/"<<endl;
person hututuNew = j2.get<person>();//像basic value一樣通過get函數(shù)獲取值,將其值直接賦值給自定義對(duì)象
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 宏的使用
可以看出上述的宏主要實(shí)現(xiàn)了from_json和to_json兩個(gè)函數(shù)的功能,使用時(shí)需要在一個(gè)類中調(diào)用該宏,并傳入(類名,參數(shù)1,參數(shù)2,參數(shù)3…)使用,這樣在json對(duì)象和class對(duì)象之間之間直接賦值可以完成相互轉(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};//定義一個(gè)person對(duì)象為hututu
cout<<"/----------調(diào)用宏實(shí)現(xiàn):to json-----------/"<<endl;
json j1 = hututu;
cout << j1<< endl;
cout << j1.dump() << endl;
cout<<"/----------調(diào)用宏實(shí)現(xiàn):from json-----------/"<<endl;
j1["name"]="new name";
person hututu_new = j1;
hututu_new.display();
return 0;
}
輸出結(jié)果:
/----------調(diào)用宏實(shí)現(xiàn):to json-----------/
{“age”:18,“name”:“hututu”,“score”:88.99}
{“age”:18,“name”:“hututu”,“score”:88.99}
/----------調(diào)用宏實(shí)現(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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Visual Studio 2022無法打開源文件的解決方式
這篇文章主要介紹了Visual Studio 2022無法打開源文件的解決方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-01-01
C++實(shí)現(xiàn)雙目立體匹配Census算法的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用C++實(shí)現(xiàn)雙目立體匹配Census算法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2022-08-08
VS2019開發(fā)簡(jiǎn)單的C/C++動(dòng)態(tài)鏈接庫并進(jìn)行調(diào)用的實(shí)現(xiàn)
這篇文章主要介紹了VS2019開發(fā)簡(jiǎn)單的C/C++動(dòng)態(tài)鏈接庫并進(jìn)行調(diào)用的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03
C++實(shí)例分析講解臨時(shí)對(duì)象與右值引用的用法
對(duì)性能來說,許多的問題都需要和出現(xiàn)頻率及本身執(zhí)行一次的開銷掛鉤,有些問題雖然看似比較開銷較大,但是很少會(huì)執(zhí)行到,那也不會(huì)對(duì)程序有大的影響;同樣一個(gè)很小開銷的函數(shù)執(zhí)行很頻繁,同樣會(huì)對(duì)程序的執(zhí)行效率有很大影響。本章中作者主要根據(jù)臨時(shí)對(duì)象來闡述這樣一個(gè)觀點(diǎn)2022-08-08
一文帶你學(xué)習(xí)C++析構(gòu)函數(shù)
在C++中,析構(gòu)函數(shù)是一種特殊類型的成員函數(shù),用于在對(duì)象生命周期結(jié)束時(shí)被自動(dòng)調(diào)用,本文我們將介紹C++析構(gòu)函數(shù)的一些重要知識(shí)點(diǎn),并提供相應(yīng)代碼示例,需要的朋友可以參考下2023-05-05
C++控制臺(tái)循環(huán)鏈表實(shí)現(xiàn)貪吃蛇
這篇文章主要為大家詳細(xì)介紹了C++控制臺(tái)循環(huán)鏈表實(shí)現(xiàn)貪吃蛇,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-04-04
C語言詳解如何實(shí)現(xiàn)帶頭雙向循環(huán)鏈表
帶頭雙向循環(huán)鏈表:結(jié)構(gòu)最復(fù)雜,一般用在單獨(dú)存儲(chǔ)數(shù)據(jù)。實(shí)際中使用的鏈表數(shù)據(jù)結(jié)構(gòu),都是帶頭雙向循環(huán)鏈表。另外這個(gè)結(jié)構(gòu)雖然結(jié)構(gòu)復(fù)雜,但是使用代碼實(shí)現(xiàn)以后會(huì)發(fā)現(xiàn)結(jié)構(gòu)會(huì)帶來很多優(yōu)勢(shì),實(shí)現(xiàn)反而簡(jiǎn)單2022-04-04

