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 与 Patch1、_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

在这里插入图片描述

优化后代码:

#include <iostream>
//  json.hpp 唯一需要引入的文件
#include <nlohmann/json.hpp>
#include <fstream>
#include <iomanip>
// 使用如下语句方便使用
using json = nlohmann::json;

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];
            from_json(j["pieces"][i],t.pieces[i] );
        }
        t.size = j["pieces"].size();
    }

    /// j: json文件中 output 部分 , v: 结构体 outputinfo
    void to_json(const outputinfo &v, json &j) {
        j["width"] = v.width;
        j["height"] = v.height;
        j["frameRate"] = v.frameRate;
        j["crf"] = v.crf;
    }

    void to_json(const pieceinfo &p ,json &j) {
        j["file"] = p.pathname;
        j["startTime"] = p.startTime;
        j["endTime"] = p.endTime;
    }

    /// j: json文件中 tracks 部分 , v: 结构体 trackinfo
    void to_json(const trackinfo &t,json &j) {
        j["name"] = t.name;
        /// 遍历 tracks 中 多个 pieces
        int len = t.size;
        for(int i = 0; i < len; i++) {
            to_json(t.pieces[i],j["pieces"][i]);
        }
    }

}

/**
 * 1、从 json文件读取为结构体
 * 2、将结构体按json格式存到文件
 * @return
 */
int main() {
    std::cout << "Hello, World!" << std::endl;

    /****** 从json文件中读取数据 并 存放为结构体******/
    json j;
    std::fstream jfile;
    jfile.open("Complex.json");

    jfile >> j;
    jfile.close();
    std::cout << "json j = " << j << std::endl;

    ///jsonns::outputinfo vi = j.at("output");
    jsonns::outputinfo vi{};
    jsonns::from_json(j.at("output"),vi);

    /// 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];
        jsonns::from_json(j["tracks"][i],ti[i]);
    }
    /****** 从json文件中读取数据 并 存放为结构体 end******/

    /******* 将结构体数据存成json对象 并 写入文件 ******/
    json j2;
    // "output" 数据
    jsonns::to_json(vi,j2["output"]);
    int tiSize = ti->size;
    for (int i = 0; i < tiSize; i++) {
        to_json(ti[i],j2["tracks"][i]);
    }

    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;
}

利用宏列化/反序列结构体

如果您只想序列化/反序列化某些结构,则to_json / from_json函数可能是很多样板,可以利用两个宏来简化你的编码。

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(name, member1, member2, ...) 将在要为其创建代码的类/结构的命名空间内定义。

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

两个宏定义如下,其用到了可变参数宏的展开,宏重载相关内容,参见不定参数宏展开与__VA_ARGS__

/*!
@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__)) }

代码:MacrosForSerialization

#include <iostream>
#include <iomanip>
#include "json.hpp"

using json = nlohmann::json;

class Address {

public:
    Address(){
        postcode = 1024;
        housenumber = 100;
        street = "this is a address";
    }
    ~Address() = default;
    int postcode;

public:
    void show(){
        std::cout << "postcode = "  << postcode << std::endl;
        std::cout << "housenumber = "  << housenumber << std::endl;
        std::cout << "street = "  << street << std::endl;
    }
    NLOHMANN_DEFINE_TYPE_INTRUSIVE(Address, street, housenumber, postcode)
    //NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Address, street, housenumber, postcode) // 存在 private 不能使用 这个宏

private:
    std::string street;
    int housenumber;

};

namespace ns {

    struct Student {
        int age{};
        int num{};
        std::string name;
    };
    NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Student, age, num, name)
}

int main() {
    Address add1;
    add1.postcode = 4096;
    json j1 = add1;
    std::cout << std::setw(4) << j1 <<std::endl;
    Address add2;
    add2 = j1;
    add2.show();

    ns::Student st1;
    st1.name = "张三";
    st1.num = 1;
    st1.age = 18;
    json j2 = st1;
    std::cout << std::setw(4) << j2 <<std::endl;
    ns::Student st2;
    st2 = j2;
    std::cout << "st2.name = "  << st2.name << std::endl;
    std::cout << "st2.num = "  << st2.num << std::endl;
    std::cout << "st2.age = "  << st2.age << std::endl;
    
    return 0;
}

输出:

{
    "housenumber": 100,
    "postcode": 4096,
    "street": "this is a address"
}
postcode = 4096
housenumber = 100
street = this is a address
{
    "age": 18,
    "name": "张三",
    "num": 1
}
st2.name = 张三
st2.num = 1
st2.age = 18

Process finished with exit code 0

希望我的文章对于大家有帮助,由于个人能力的局限性,文中可能存在一些问题,欢迎指正、补充!

  • 4
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

墨1024

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值