json for modern c++,这是我用过的最好用的json库了

从渊
2023-12-01

GitHub开源项的地址:https://github.com/nlohmann/json

json for modern c++是一个德国大牛nlohmann写的,有以下特点:

1.直观的语法。
2.整个代码由一个头文件组成json.hpp,没有子项目,没有依赖关系,没有复杂的构建系统,使用起来非常方便。
3.使用c++11标准编写。
4.使用json 像使用STL容器一样。
5.STL和json容器之间可以相互转换。
还有很多其他的特性,不一一列举了。

如何使用?

将github上的src文件夹里的json.hpp头文件下载保存到当前目录中。
在代码中包含json.hpp头文件并引入json作用域

#include "json.hpp"
using json = nlohmann::json;

 

常用功能:

一.创建json对象

1.使用cin,cout输入输出流。
json提供了cin,cout的输入输出流的操作符。但需要注意的是,cin要有ctr + D结束输入。cin会把从标准输入的内容反序列化,cout会自动把json序列化,以string形式输出。

#include<iostream>
#include"json.hpp"
using namespace std;
using json=nlohmann::json;

int main()
{
    json j;  //创建json类
    cin>>j;   //从cin读入json字符串,必须是合法的json字符串
    cout<<j;  //输出序列化的json
    return 0;
}

2.提供根据键直接生成键值对的方法。(类似于map,如果不存在该键的话,就生成一个这个键。)

#include <iostream>
#include "json.hpp"
using json = nlohmann::json;
using namespace std;

int main() {
    // 创建一个json对象(null)
    json j;

    //添加一个存储为double的数字
    j["pi"] = 3.141;

    // 添加一个布尔值 
    j["happy"] = true;

    // 添加一个存储为std :: string的字符串
    j["name"] = "Niels";

    // 通过传递nullptr添加另一个空对象
    j["nothing"] = nullptr;

    // 在对象中添加对象
    j["answer"]["everything"] = 42;

    //添加一个数组,其存储为std::vector(使用初始化列表)
    j["list"] = { 1, 0, 2 };

    // 在一个对象中添加另一个对象
    j["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}
        }}
    };
    cout << j << endl;
    cout << endl;
    cout << j2 << endl;
    return 0;
}

 

3.在所有上述情况下,你不需要“告诉”编译器要使用哪个JSON值。如果你想明确或表达一些边缘的情况下,可以使用json::array,json::object。

#include <iostream>
#include "json.hpp"
using json = nlohmann::json;
using namespace std;

int main() {
    //创建一个空数组
    json empty_array_explicit = json::array();

    // 创建一个空对象的两种方式
    json empty_object_implicit = json({});
    json empty_object_explicit = json::object();
}

 

4.几点注意
1).array是一个数组,可以用数字直接下标访问。

json array = {
        "a",6,"xin",8
    };
cout << array[0] << endl;

 

2)数组中包含一个数组

json array = {
        {"a",6},
        "xin",8
    };
cout << array[0][0] << endl;  //输出数组里的数组元素中的第一个元素的值

 

3)数组中包含一个对象

json array = {
        {{"a",6}},
        "xin",8
    };
//输出数组中第一个元素"a"对应的键值
cout << array[0]["a"] << endl;

 

4).对象中嵌套一个对象和一个数组

json object = {
        {"a",{{"feng",6}}},{"b",{1,2,3}}
    };
    cout << object << endl;
/*输出:
{"a":{"feng":6},"b":[1,2,3]}
*/

 

二.序列化

将json对象序列化,成为字符串

1.标准输出自动序列化

json j
std :: cout << j;
// setw操纵器被重载以设置漂亮打印的缩进 
std :: cout << std :: setw( 4)<< j << std :: endl;

 

2.使用dump()函数

//显式转换为string 
std::string s = j.dump();    // {\"happy\":true,\"pi\":3.141}

//序列化与漂亮的打印
//传入空格的数量缩进 
std::cout << j.dump(4) << std::endl;
// 输出:
//{
//     "happy": true,
//     "pi": 3.141
// }

 

三.反序列化

将数据流转化为json对象

1.从标准输入反序列化

json j
std :: cin >> j;

 

2.通过附加_json到字符串文字来创建对象(反序列化):

//从字符串文字创建对象 
json j = " { \" happy \":true,\" pi \":3.141} " _json;

//或者原始字符串文字
auto j2 = R"(
   { 
    "happy":true,
    "pi":3.141 
  } 
)" _json;

 

请注意,没有附加_json后缀,传递的字符串文字不会被解析,而只是用作JSON字符串值。也就是说,json j = "{ \"happy\": true, \"pi\": 3.141 }"只存储字符串"{ "happy": true, "pi": 3.141 }"而不是解析实际的对象。

3.使用json::parse()函数

//明确解析
auto j3 = json::parse(" { \" happy \":true,\" pi \":3.141} ");

 

4.从迭代器范围读取

您还可以从迭代器范围读取JSON; 也就是说,可以从其内容存储为连续字节序列的迭代器访问的任何容器,例如std::vector

std :: vector < uint8_t > v = { ' t ',' r ',' u ',' e ' };
json j = json :: parse(v.begin(),v.end());

//或
std :: vector < uint8_t > v = { ' t ',' r ',' u ',' e ' };
json j = json :: parse(v);

 

四.与STL适应

nlohmann设计的JSON类,就像一个STL容器一样。其实它满足了可逆容器要求。

//使用push_back创建一个数组
json j;
j.push_back("foo");
j.push_back(1);
j.push_back(true);

// 也可以使用emplace_back 
j.emplace_back(1.78);

// 使用迭代器访问
for (json::iterator it = j.begin(); it != j.end(); ++it) {
  std::cout << *it << '\n';
}

// 基于范围for循环
for (auto& element : j) {
  std::cout << element << '\n';
}

// 赋值操作
const std::string tmp = j[0];
j[1] = 42;
bool foo = j.at(2);

// 比较操作
j == "[\"foo\", 1, true]"_json;  // true

// 其他函数
j.size();     // 3 
j.empty();    // false
j.type();     // json::value_t::array
j.clear();    // 使数组再次为空

// 方便类型检查
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");

// 使用迭代器输出
for (json::iterator it = o.begin(); it != o.end(); ++it) {
  std::cout << it.key() << " : " << it.value() << "\n";
}

// 使用find函数
if (o.find("foo") != o.end()) {
  // there is an entry with key "foo"
}

// count函数
int foo_present = o.count("foo"); // 1
int fob_present = o.count("fob"); // 0

// 删除条目 
o.erase("foo");

 

五.从STL容器转换

任何序列容器(std::array,std::vector,std::deque,std::forward_list,std::list),其值可以被用于构建JSON类型(例如,整数,浮点数,布尔值,字符串类型,或者再次在本节中描述STL容器)可被用于创建JSON阵列。这同样适用于类似的关联容器(std::set,std::multiset,std::unordered_set,std::unordered_multiset),但是在这些情况下,阵列的元素的顺序取决于元素是如何在各个STL容器排序。

std::vector<int> c_vector {1, 2, 3, 4};
json j_vec(c_vector);
// [1, 2, 3, 4]

std::deque<double> c_deque {1.2, 2.3, 3.4, 5.6};
json j_deque(c_deque);
// [1.2, 2.3, 3.4, 5.6]

std::list<bool> c_list {true, true, false, true};
json j_list(c_list);
// [true, true, false, true]

std::forward_list<int64_t> c_flist {12345678909876, 23456789098765, 34567890987654, 45678909876543};
json j_flist(c_flist);
// [12345678909876, 23456789098765, 34567890987654, 45678909876543]

std::array<unsigned long, 4> c_array {{1, 2, 3, 4}};
json j_array(c_array);
// [1, 2, 3, 4]

std::set<std::string> c_set {"one", "two", "three", "four", "one"};
json j_set(c_set); // only one entry for "one" is used
// ["four", "one", "three", "two"]

std::unordered_set<std::string> c_uset {"one", "two", "three", "four", "one"};
json j_uset(c_uset); // only one entry for "one" is used
// maybe ["two", "three", "four", "one"]

std::multiset<std::string> c_mset {"one", "two", "one", "four"};
json j_mset(c_mset); // both entries for "one" are used
// maybe ["one", "two", "one", "four"]

std::unordered_multiset<std::string> c_umset {"one", "two", "one", "four"};
json j_umset(c_umset); // both entries for "one" are used
// maybe ["one", "two", "one", "four"]

 

同样,任何键值容器(std::map,std::multimap,std::unordered_map,std::unordered_multimap),其键可以构造一个std::string,并且其值可以被用于构建JSON类型(参见上文实施例)可用于创建一个JSON对象。请注意,在多重映射的情况下,JSON对象中仅使用一个键,该值取决于STL容器的内部顺序。

std::map<std::string, int> c_map { {"one", 1}, {"two", 2}, {"three", 3} };
json j_map(c_map);
// {"one": 1, "three": 3, "two": 2 }

std::unordered_map<const char*, double> c_umap { {"one", 1.2}, {"two", 2.3}, {"three", 3.4} };
json j_umap(c_umap);
// {"one": 1.2, "two": 2.3, "three": 3.4}

std::multimap<std::string, bool> c_mmap { {"one", true}, {"two", true}, {"three", false}, {"three", true} };
json j_mmap(c_mmap); // only one entry for key "three" is used
// maybe {"one": true, "two": true, "three": true}

std::unordered_multimap<std::string, bool> c_ummap { {"one", true}, {"two", true}, {"three", false}, {"three", true} };
json j_ummap(c_ummap); // only one entry for key "three" is used
// maybe {"one": true, "two": true, "three": true}

 

六.隐式转换

JSON对象的类型由要存储的表达式自动确定。同样,存储的值被隐式转换。

// strings 
std :: string s1 = “ Hello,world!” ;
json js = s1;
std :: string s2 = js;

// Booleans 
bool b1 = true ;
json jb = b1;
bool b2 = jb;

// numbers 
int i = 42 ;
json jn = i;
double f = jn;

//...

 

还可以明确指定转换的类型:

std :: string vs = js.get <std :: string>();
bool vb = jb.get < bool >();
int vi = jn.get < int >();

 

七.任意类型转换

每个类型都可以以JSON序列化,而不仅仅是STL容器和标量类型。通常情况下,你会做这些事情:

namespace ns {
    struct person {
        std::string name;
        std::string address;
        int age;
    };
}

ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60};

// 转换为JSON:将每个值复制到JSON对象中
json j;
j["name"] = p.name;
j["address"] = p.address;
j["age"] = p.age;

// ...

// 从JSON转换:从JSON对象复制每个值
ns::person p {
    j["name"].get<std::string>(),
    j["address"].get<std::string>(),
    j["age"].get<int>()
};

 

或者,使用一种更简便的用法

// 创建一个person类并初始化
ns::person p {"Ned Flanders", "744 Evergreen Terrace", 60};

// 隐式转换: person -> json
json j = p;

std::cout << j << std::endl;
// {"address":"744 Evergreen Terrace","age":60,"name":"Ned Flanders"}

// 隐式转换: json -> person
ns::person p2 = j;

// 测试是否完全相同
assert(p == p2);

 

以上是对json for modern c++基本功能的使用总结,如有哪里有误,欢迎指出,相互学习交流。

 类似资料: