JSON for Modern C++ 庫的介紹與使用示例程式碼
JSON for Modern C++ 介紹
相關連結
GitHub:https://github.com/nlohmann/json
api文件:https://nlohmann.github.io/json/api/basic_json/
標頭檔案新增
// json.hpp 唯一需要引入的檔案
#include <nlohmann/json.hpp>
// 使用如下語句方便使用
using json = nlohmann::json;
CMakeLists 新增
find_package(nlohmann_json 3.2.0 REQUIRED) # 找包
target_link_libraries(${PROJECT_NAME}
PRIVATE
nlohmann_json::nlohmann_json) # link 庫
示例程式碼
示例 | 說明 |
---|---|
簡單使用 | json物件的建立 |
序列化與反序列化 | 1、字串的序列化與反序列化 2、流的序列化與反序列化(輸入輸出流+檔案流) |
像STL一樣操作json物件 | json物件形如STL操作的方法使用 |
Json Pointer 與 Patch | 1、_json_pointer 的使用 2、patch與merge_patch的補丁操作 |
解析簡單json檔案 | 讀取簡單json檔案,並將資料存放到不容變數中 |
解析json檔案為結構體以及將結構存放為json檔案 | 1、讀取json檔案多級資料並存放為結構體,int 、string、陣列 2、將結構體資料迴圈處理後存放入json檔案 |
簡單使用
demo: SimpleUseTest
程式碼: GitHub SimpleUseTest
#include <iostream>
// json.hpp 唯一需要引入的檔案
#include <nlohmann/json.hpp>
// 使用如下語句方便使用
using json = nlohmann::json;
int main() {
/// 簡單使用
//建立一個空的結構
json j1;
// 數字 儲存為 double
j1["pi"] = 3.141;
// Boolean 儲存為 bool
j1["happy"] = true;
// 字串 儲存為 std::string
j1["name"] = "Niels";
// 空值 傳入 nullptr
j1["nothing"] = nullptr;
// 直接加入其他物件
j1["answer"]["everything"] = 42;
// 加入一個 array 儲存為 std::vector (使用初始化列表)
j1["list"] = { 1, 0, 2 };
// 新增其他物件 (使用鍵值對初始化列表)
j1["object"] = { {"currency", "USD"}, {"value", 42.99} };
// 直接形如json格式進行初始化
json j2 = {
{"pi", 3.141},
{"happy", true},
{"name", "Niels"},
{"nothing", nullptr},
{"answer", {
{"everything", 42}
}},
{"list", {1, 0, 2}},
{"object", {
{"currency", "USD"},
{"value", 42.99}
}}
};
std::cout << "json j1 = " << j1 << std::endl;
std::cout << "json j2 = " << j2 << std::endl;
///可使用函式 json::array() 和 json::object() 等 顯示錶示
// 空陣列
json empty_array_explicit = json::array();
// 空 {} 物件
json empty_object_implicit = json({});
json empty_object_explicit = json::object();
// 通過 key/value 鍵值對建立陣列 [["currency", "USD"], ["value", 42.99]]
json array_not_object = json::array({ {"currency", "USD"}, {"value", 42.99} });
std::cout << "json empty_array_explicit = " << empty_array_explicit << std::endl;
std::cout << "json empty_object_implicit = " << empty_object_implicit << std::endl;
std::cout << "json empty_object_explicit = " << empty_object_explicit << std::endl;
std::cout << "json array_not_object = " << array_not_object << std::endl;
std::cout << "json array_not_object[?][?] = " << array_not_object[1] << std::endl;
return 0;
}
輸出:
json j1 = {"answer":{"everything":42},"happy":true,"list":[1,0,2],"name":"Niels","nothing":null,"object":{"currency":"USD","value":42.99},"pi":3.141}
json j2 = {"answer":{"everything":42},"happy":true,"list":[1,0,2],"name":"Niels","nothing":null,"object":{"currency":"USD","value":42.99},"pi":3.141}
json empty_array_explicit = []
json empty_object_implicit = {}
json empty_object_explicit = {}
json array_not_object = [["currency","USD"],["value",42.99]]
json array_not_object[?][?] = ["value",42.99]
Process finished with exit code 0
序列化與反序列化
demo:SerializationAndDeserialization
程式碼: GitHub SerializationAndDeserialization
#include <iostream>
#include <nlohmann/json.hpp>
#include <iomanip>
#include <fstream>
using json = nlohmann::json;
int main() {
/// 字串 序列化與反序列化
// 通過新增 _json 字尾將字串反序列化為json變數
json j1 = "{ \"happy\": true, \"pi\": 3.141 }"_json;
// 最好使用原始字串
auto j2 = R"({"happy": true,"pi": 3.141})"_json;
// 使用 json::parse() 顯示使用
auto j3 = json::parse(R"({ "happy": true, "pi": 3.141 })");
std::cout << "json j1" << j1 << std::endl;
std::cout << "json j2" << j2 << std::endl;
std::cout << "json j3" << j3 << std::endl;
// 將json變數序列化為 字串 .dump()返回最初儲存的字串值。 dump() dump(4) 4 顯示格式便於檢視
std::string s = j3.dump(); // {"happy":true,"pi":3.141}
std::cout << "string s j3.dump()" << s << std::endl;
std::cout << "string s j3.dump(4)" << j3.dump(4) << std::endl;
/// 序列化和賦值之間的區別
/// 庫只支援UTF-8 儲存具有不同編碼的字串時,呼叫dump()可能會引發異常
// 將字串儲存在JSON值中
json j_string = "this is a string";
std::cout << "json j_string = " << j_string << std::endl;
// 獲取字串值 j_string.get<std::string>()
auto cpp_string = j_string.get<std::string>();
std::cout << "j_string.get<std::string>() cpp_string = " << cpp_string << std::endl;
// 獲取字串值 並存到 變數
std::string cpp_string2;
j_string.get_to(cpp_string2);
// 獲取序列化的值(顯式JSON序列化)
std::string serialized_string = j_string.dump();
// 輸出原始字串
std::cout << "original string: " << cpp_string << " == " << cpp_string2 << " == " << j_string.get<std::string>() << '\n';
// 出書序列化值
std::cout << "serialized value: " << j_string << " == " << serialized_string << std::endl;
/// 從標準輸入輸出流中 序列化與反序列化
// 從標準輸入反序列化
json j4;
std::cout << "please input:" << std::endl;
std::cin >> j4;
// 序列化到標準輸出
std::cout << j4 << std::endl;
// 格式化輸出
std::cout << std::setw(4) << j4 << std::endl;
/// 從檔案流中 序列化與反序列化
// 讀取一個json檔案
std::ifstream i("file.json");
json j5;
i >> j5;
std::cout << "json j5 = " << j5 << std::endl;
// 將美化的JSON寫入另一個檔案
std::ofstream o("pretty.json");
o << std::setw(4) << j5 << std::endl; // std::setw(4) 設定格式
return 0;
}
輸出:
json j1{"happy":true,"pi":3.141}
json j2{"happy":true,"pi":3.141}
json j3{"happy":true,"pi":3.141}
string s j3.dump(){"happy":true,"pi":3.141}
string s j3.dump(4){
"happy": true,
"pi": 3.141
}
json j_string = "this is a string"
j_string.get<std::string>() cpp_string = this is a string
original string: this is a string == this is a string == this is a string
serialized value: "this is a string" == "this is a string"
please input:
{"happy":true,"pi":3.141}
{"happy":true,"pi":3.141}
{
"happy": true,
"pi": 3.141
}
json j5 = {"output":{"crf":31,"frameRate":20,"height":1080,"width":1000},"tracks":[{"name":"t1","pieces":[{"endTime":6,"file":"x.mp4","startTime":2},{"endTime":13,"file":"y.mp4","startTime":9}]},{"name":"t2","pieces":[{"endTime":10,"file":"z.mp4","startTime":0}]}]}
Process finished with exit code 0
像STL一樣操作json物件
demo:Access_STL_like
程式碼:GitHub Access_STL_like
#include <iostream>
// json.hpp 唯一需要引入的檔案
#include <nlohmann/json.hpp>
// 使用如下語句方便使用
using json = nlohmann::json;
// 函式可參看 api : https://nlohmann.github.io/json/api/basic_json/
int main() {
// 使用 push_back 建立陣列, 將給定元素Val附加到JSON陣列的末尾
json j;
j.push_back("foo");
j.push_back(1);
j.push_back(true);
std::cout << "json j = " << j << std::endl;
// emplace_back 在j尾部 加入 根據傳遞的引數arg建立的JSON值
j.emplace_back(1.78);
std::cout << "json j = " << j << std::endl;
// 迭代器遍歷
for (json::iterator it = j.begin(); it != j.end(); ++it) {
std::cout << *it << '\n';
}
std::cout << "==============" << std::endl;
// 遍歷 j
for (auto& element : j) {
std::cout << element << '\n';
}
std::cout << "==============" << std::endl;
// 取值 設定值
const auto tmp = j[0].get<std::string>();
std::cout << "json j = " << j << std::endl;
j[1] = 42;
std::cout << "json j = " << j << std::endl;
bool foo = j.at(2);
std::cout << " j.at(2) = " << foo << std::endl;
std::cout << "==============" << std::endl;
// 是否相等
std::cout <<"j == \"[\\\"foo\\\", 42, true]\"_json : " << (j == "[\"foo\", 42, true]"_json) << std::endl;
// size
std::cout << "j.size() : " << j.size() << std::endl;
// 是否為空
std::cout << "j.empty() : " << j.empty() << std::endl;
// 型別
j.type(); // 返回型別
auto name = j.type_name(); // 將型別名稱作為字串返回
std::cout << "j.type() : " << name << std::endl;
// 清空
j.clear();
std::cout << "json j = " << j << std::endl;
std::cout << "==============" << std::endl;
// 方便的型別檢查
j.is_null();
j.is_boolean();
j.is_number();
j.is_object();
j.is_array();
j.is_string();
// 建立一個物件, 字典
json o;
o["foo"] = 23;
o["bar"] = false;
o["baz"] = 3.141;
// 也可以通過 emplace 新增新元素
o.emplace("weather", "sunny");
std::cout << "json o = " << o << std::endl;
// 迭代器遍歷
for (json::iterator it = o.begin(); it != o.end(); ++it) {
std::cout << it.key() << " : " << it.value() << "\n";
}
std::cout << "==============" << std::endl;
for (auto& el : o.items()) {
std::cout << el.key() << " : " << el.value() << "\n";
}
std::cout << "==============" << std::endl;
// 結構化繫結 (C++17)
for (auto& [key, value] : o.items()) {
std::cout << key << " : " << value << "\n";
}
std::cout << "==============" << std::endl;
// contains 查詢是否包含 key 值
if (o.contains("foo")) {
std::cout << R"(o.contains("foo"))" << std::endl;
}
// 通過 find
if (o.find("foo") != o.end()) {
std::cout << R"(o.find("foo"))" << std::endl;
}
// 通過 count 返回 key 的個數
int foo_present = o.count("foo"); // 1
int fob_present = o.count("fob"); // 0
// 刪除 某個鍵值對
o.erase("foo");
std::cout << "json o = " << o << std::endl;
return 0;
}
輸出:
json j = ["foo",1,true]
json j = ["foo",1,true,1.78]
"foo"
1
true
1.78
==============
"foo"
1
true
1.78
==============
json j = ["foo",1,true,1.78]
json j = ["foo",42,true,1.78]
j.at(2) = 1
==============
j == "[\"foo\", 42, true]"_json : 0
j.size() : 4
j.empty() : 0
j.type() : array
json j = []
==============
json o = {"bar":false,"baz":3.141,"foo":23,"weather":"sunny"}
bar : false
baz : 3.141
foo : 23
weather : "sunny"
==============
bar : false
baz : 3.141
foo : 23
weather : "sunny"
==============
bar : false
baz : 3.141
foo : 23
weather : "sunny"
==============
o.contains("foo")
o.find("foo")
json o = {"bar":false,"baz":3.141,"weather":"sunny"}
Process finished with exit code 0
Json Pointer 與 Patch
demo: JsonPointerAndPatch
程式碼:GitHub JsonPointerAndPatch
#include <iostream>
// json.hpp 唯一需要引入的檔案
#include <nlohmann/json.hpp>
// 使用如下語句方便使用
using json = nlohmann::json;
int main() {
/// _json_pointer
json j_original = R"({
"baz": ["one", "two", "three"],
"foo": "bar"
})"_json;
std::cout << "json j_original = " << j_original << std::endl;
// 通過json指標訪問成員
// 如果沒有 會新增元素其值為null
// eg: j_original["/baz/5"_json_pointer] 會在 增加元素 到 6 個
auto var1 = j_original["/baz/1"_json_pointer]; // "two"
auto var2 = j_original["/baz/2"_json_pointer]; // "three"
auto var5 = j_original["/baz/5"_json_pointer]; // null
std::cout << "var1 = " << var1 << std::endl;
std::cout << "var2 = " << var2 << std::endl;
std::cout << "var3= " << j_original["/baz/3"_json_pointer] << std::endl;
std::cout << "var4 = " << j_original["/baz/4"_json_pointer] << std::endl;
std::cout << "var5 = " << var5 << std::endl;
std::cout << "=============" << std::endl;
/// patch
// 補丁操作
// "op": 指定操作 "path":指定 key值 "value":指定值
json j_patch = R"([
{ "op": "replace", "path": "/baz", "value": "boo" },
{ "op": "add", "path": "/hello", "value": ["world"] },
{ "op": "remove", "path": "/foo"}
])"_json;
// 執行補丁, 不會修改原資料,返回修改後的資料
json j_result = j_original.patch(j_patch);
std::cout << "json j_original = " << j_original << std::endl;
std::cout << "json j_result = " << j_result << std::endl;
// {
// "baz": "boo",
// "hello": ["world"]
// }
// 建立一個JSON Patch,以便通過呼叫修補程式函式將 源值(j_original) 更改為 目標值(j_result)
// 故 source.patch(diff(source, target)) == target; 總是為 true
auto op_patch = json::diff(j_result, j_original);
std::cout << "op_patch = " << op_patch << std::endl;
// [
// { "op":" replace", "path": "/baz", "value": ["one", "two", "three"] },
// { "op": "remove","path": "/hello" },
// { "op": "add", "path": "/foo", "value": "bar" }
// ]
std::cout << "=============" << std::endl;
/// Merge Patch
// 可以不是用_json_pointer而是使用 merge_patch 來修改元素
// 根據 j_patch 的值,操作 原資料
json j_document = R"({
"a": "b",
"c": {
"d": "e",
"f": "g"
}
})"_json;
std::cout << "json j_document = " << j_document << std::endl;
// a patch
json j_patch2 = R"({
"a":"z",
"c": {
"f": null
}
})"_json;
std::cout << "json j_patch2 = " << j_patch2 << std::endl;
j_document.merge_patch(j_patch);
std::cout << "json j_document = " << j_document << std::endl;
// {
// "a": "z",
// "c": {
// "d": "e"
// }
// }
std::cout << "=============" << std::endl;
return 0;
}
輸出:
json j_original = {"baz":["one","two","three"],"foo":"bar"}
var1 = "two"
var2 = "three"
var3= null
var4 = null
var5 = null
=============
json j_original = {"baz":["one","two","three",null,null,null],"foo":"bar"}
json j_result = {"baz":"boo","hello":["world"]}
op_patch = [{"op":"replace","path":"/baz","value":["one","two","three",null,null,null]},{"op":"remove","path":"/hello"},{"op":"add","path":"/foo","value":"bar"}]
=============
json j_document = {"a":"b","c":{"d":"e","f":"g"}}
json j_patch2 = {"a":"z","c":{"f":null}}
json j_document = [{"op":"replace","path":"/baz","value":"boo"},{"op":"add","path":"/hello","value":["world"]},{"op":"remove","path":"/foo"}]
=============
Process finished with exit code 0
解析簡單json檔案
demo: ParseJsonFileSimple
程式碼:GitHub ParseJsonFileSimple
#include <iostream>
#include <fstream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
/**
simple.json 檔案
{
"ok":true,
"height": 20.123,
"width": 1000,
"name": "test"
}
*/
int main() {
json j; // json 物件
std::ifstream jfile("simple.json"); // 流讀取
jfile >> j; // 檔案流形式讀取 json 檔案, 並存為 j
jfile.close();
std::cout << "json j = " << j << std::endl;
bool ok = j.at("ok");
float height = j["height"];
int width = j["width"];
std::string name = j.at("name");
std::cout << "ok = " << ok << std::endl;
std::cout << "height = " << height << std::endl;
std::cout << "width = " << width << std::endl;
std::cout << "name = " << name << std::endl;
return 0;
}
輸出:
json j = {"height":20.123,"name":"test","ok":true,"width":1000}
ok = 1
height = 20.123
width = 1000
name = test
Process finished with exit code 0
解析json檔案為結構體以及將結構存放為json檔案
demo:ParseJsonFileComplex
程式碼:GitHub ParseJsonFileComplex
#include <iostream>
// json.hpp 唯一需要引入的檔案
#include <nlohmann/json.hpp>
#include <fstream>
#include <iomanip>
// 使用如下語句方便使用
using json = nlohmann::json;
/*
Complex.json 檔案
{
"output": {
"width": 720,
"height": 1080,
"frameRate": 20,
"crf": 31
},
"tracks": [
{
"name": "t1",
"pieces": [
{
"file": "x.mp4",
"startTime": 2,
"endTime": 6
},
{
"file": "y.mp4",
"startTime": 9,
"endTime": 13
}
]
},
{
"name": "t2",
"pieces": [
{
"file": "z.mp4",
"startTime": 0,
"endTime": 10
}
]
}
]
}
*/
///從這個 json 檔案,可以看到,它包括兩大部分 "output" 和 "tracks"。
/// "tracks" 為陣列有兩個元素,包括 string 的 name,和另一個結構體 "pieces" 的陣列。
/// 可以定義 3個結構體 outputinfo pieceinfo trackinfo
namespace jsonns {
struct outputinfo {
int width;
int height;
int frameRate;
int crf;
};
struct pieceinfo {
std::string pathname;
int startTime{};
int endTime{};
};
struct trackinfo {
std::string name;
pieceinfo pieces[5];
int size{};
};
/// j: json檔案中 output 部分 , v: 結構體 outputinfo
void from_json(const json& j, outputinfo& v) {
j.at("width").get_to(v.width);
j.at("height").get_to(v.height);
j.at("frameRate").get_to(v.frameRate);
j.at("crf").get_to(v.crf);
}
/// j: json檔案中 pieces 部分 , v: 結構體 pieceinfo
void from_json(const json&j, pieceinfo &p) {
j.at("file").get_to(p.pathname);
j.at("startTime").get_to(p.startTime);
j.at("endTime").get_to(p.endTime);
}
/// j: json檔案中 tracks 部分 , v: 結構體 trackinfo
void from_json(const json&j, trackinfo &t) {
j.at("name").get_to(t.name);
/// 遍歷 tracks 中 多個 pieces
int len = j["pieces"].size();
for(int i = 0; i < len; i++) {
t.pieces[i] = j["pieces"][i];
}
t.size = j["pieces"].size();
}
}
/**
* 1、從 json檔案讀取資料並存為結構體
* 2、將結構體按json格式存到檔案
* @return
*/
int main() {
std::cout << "Hello, World!" << std::endl;
/****** 從json檔案中讀取資料 並 存放為結構體******/
json j;
std::ifstream jfile("Complex.json");
jfile >> j;
jfile.close();
std::cout << "json j = " << j << std::endl;
jsonns::outputinfo vi = j.at("output");
/// tilength json檔案中key = "tracks"值的大小
int tilength = j["tracks"].size();
/// 建立 trackinfo 陣列
jsonns::trackinfo ti[tilength];
/// 填充資料
for (int i = 0; i < tilength; i++) {
ti[i] = j["tracks"][i];
}
/****** 從json檔案中讀取資料 並 存放為結構體 end******/
/******* 將結構體資料存成json物件 並 寫入檔案 ******/
json j2;
// "output" 資料
j2["output"]["width"] = vi.width;
j2["output"]["height"] = vi.height;
j2["output"]["frameRate"] = vi.frameRate;
j2["output"]["crf"] = vi.crf;
// "tracks" 資料, 是個陣列
json tracks;
for (int i = 0; i < tilength; i++) {
json ttmp;
ttmp["name"] = ti[i].name;
int len = ti[i].size; // pieces 多少個
// "pieces" 資料 是個陣列
json pieces;
for (int k = 0; k < len; ++k) {
json ptmp;
ptmp["file"] = ti[i].pieces[k].pathname;
ptmp["startTime"] = ti[i].pieces[k].startTime;
ptmp["endTime"] = ti[i].pieces[k].endTime;
pieces.push_back(ptmp); // 是 陣列 通過 push_back 新增
}
ttmp["pieces"] = pieces;
tracks.push_back(ttmp); // 是 陣列 通過 push_back 新增
}
j2["tracks"] = tracks;
std::cout << "json j2 = " << j2 << std::endl;
std::ofstream o("pretty.json");
o << std::setw(4) << j2 << std::endl; // std::setw(4) 設定格式
o.close();
/******* 將結構體資料存成json物件 並 寫入檔案 end******/
return 0;
}
輸出:
Hello, World!
json j = {"output":{"crf":31,"frameRate":20,"height":1080,"width":720},"tracks":[{"name":"t1","pieces":[{"endTime":6,"file":"x.mp4","startTime":2},{"endTime":13,"file":"y.mp4","startTime":9}]},{"name":"t2","pieces":[{"endTime":10,"file":"z.mp4","startTime":0}]}]}
json j2 = {"output":{"crf":31,"frameRate":20,"height":1080,"width":720},"tracks":[{"name":"t1","pieces":[{"endTime":6,"file":"x.mp4","startTime":2},{"endTime":13,"file":"y.mp4","startTime":9}]},{"name":"t2","pieces":[{"endTime":10,"file":"z.mp4","startTime":0}]}]}
Process finished with exit code 0
相關文章
- useRoute 函式的詳細介紹與使用示例函式
- [譯]WebAssembly: 帶有程式碼示例的簡單介紹Web
- js中的JSON介紹與案例JSON
- JSON簡介(java中的json庫使用)JSONJava
- 物件導向設計介紹和程式碼示例物件
- Cron表示式介紹與示例
- netcat 命令介紹及使用示例
- Shell指令碼介紹與使用指令碼
- JSON 介紹JSON
- C++標準庫、C++標準模版庫介紹C++
- XML和JSON的介紹XMLJSON
- JQuery的介紹與使用jQuery
- MySQL多版本併發控制MVCC的實現示例程式碼介紹MySqlMVC
- 透過示例程式碼介紹Docker部署Mysql叢集的實現DockerMySql
- Guava併發:ListenableFuture使用介紹以及示例Guava
- JSON簡單介紹JSON
- xtrabackup 2.4 的介紹與使用
- item的介紹與使用-2.0
- FastAPI 的路由介紹與使用ASTAPI路由
- Go 標準庫之 GoRequests 介紹與基本使用Go
- GoogleTagManager 介紹與使用Go
- Influxdb 介紹與使用UX
- OutputStreamWriter介紹&程式碼實現和InputStreamReader介紹&程式碼實現
- 【TcaplusDB知識庫】PB表 C++ 示例程式碼-更新資料C++
- 【Effective Modern C++】索引C++索引
- 程式碼管理工具介紹——Git與GitHubGithub
- Modern CMake 簡介
- Go 常用標準庫之 fmt 介紹與基本使用Go
- domutils 工具庫的使用方法介紹
- JSON物件簡單介紹JSON物件
- FFT原理及C++與MATLAB混合程式設計詳細介紹FFTC++Matlab程式設計
- 【TcaplusDB知識庫】PB表 C++ 示例程式碼-讀取資料C++
- 【TcaplusDB知識庫】PB表C++示例程式碼-刪除資料C++
- java ShutdownHook介紹與使用JavaHook
- IIS Express介紹與使用Express
- C++實現管理系統的示例程式碼C++
- css新手教程之背景圖充滿整個螢幕的示例程式碼介紹CSS
- c++實現Json庫C++JSON