nlohmann/json是一个用于解析JSON的开源 C++ 库,口碑一流,使用非常方便直观,是很多 C++ 程序员的首选。
通过github可以获取到源码。参考其README可以快速了解使用方法。
nlohmman/json的使用也非常简单,将include/nlohmann/json文件夹拷贝到工程中,添加路径即可使用其头文件

1
2
3
#include "nlohmman/json
nlohmman::json a;
using json = nlohmman::json;

构建JSON对象

创建一个如下的格式JSON对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"pi": 3.141,
"happy": true,
"name": "Niels",
"nothing": null,
"answer": {
"everything": 42
},
"list": [1, 0, 2],
"object": {
"currency": "USD",
"value": 42.99
}
}

使用以下方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
nlohmman::json j;
j["pi"] = 3.141;
j["happy"] = true;
j["name"] = "Niels";
j["nothing"] = nullptr;
j["answer"]["everything"] = 42;
j["list"] = {1, 0, 2 }; // 使用列表初始化的方法对"list"数组初始化
j["object"] = { {"currency", "USD"}, {"value", 42.99} }; // 初始化object对象

# 或者直接使用:
nlohmman::json j2 = {
{"pi", 3.141},
{"happy", true},
{"name", "Niels"},
{"nothing", nullptr},
{"answer", {
{"everything", 42}
}},
{"list", {1, 0, 2}},
{"object", {
{"currency", "USD"},
{"value", 42.99}
}}
};

# 调用dump()将json转为std::string
std::string str = j2.dump();

在进行如上方式构造 JSON 对象时,你并不需要告诉编译器你要使用哪种类型,nlohmann 会自动进行隐式转换。对应如下:

string序列化和反序列化

  • 反序列化:从std::string恢复JSON对象。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // create object from string literal
    json j = "{ \"happy\": true, \"pi\": 3.141 }"_json;

    // or even nicer with a raw string literal
    auto j2 = R"(
    {
    "happy": true,
    "pi": 3.141
    }
    )"_json;

    // parse explicitly
    auto j3 = json::parse(R"({"happy": true, "pi": 3.141})");
  • 序列化:Json转std::string

    1
    2
    3
    4
    5
    6
    7
    8
    9
    std::string s = j.dump();    // {\"happy\":true,\"pi\":3.141}

    // serialization with pretty printing
    // pass in the amount of spaces to indent
    std::cout << j.dump(4) << std::endl;
    // {
    // "happy": true,
    // "pi": 3.141
    // }

    注意区分序列化和设置std::string value:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // store a string in a JSON value
    json j_string = "this is a string";

    // retrieve the string value
    auto cpp_string = j_string.get<std::string>();
    // retrieve the string value (alternative when an variable already exists)
    std::string cpp_string2;
    j_string.get_to(cpp_string2);

    // retrieve the serialized value (explicit JSON serialization)
    std::string serialized_string = j_string.dump();

    // output of original string
    std::cout << cpp_string << " == " << cpp_string2 << " == " << j_string.get<std::string>() << '\n';
    // output of serialized value
    std::cout << j_string << " == " << serialized_string << std::endl;

    dump()返回 JSON 对象中存储的原始 string 值。
    该库仅支持UTF-8. 如果存储其他的编码数据,当调用dump()时,可能抛出异常。

    Note the library only supports UTF-8. When you store strings with different encodings in the library, calling dump() may throw an exception unless json::error_handler_t::replace or json::error_handler_t::ignore are used as error handlers.

  • stream和json的转换

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // deserialize from standard input
    json j;
    std::cin >> j;

    // serialize to standard output
    std::cout << j;

    // the setw manipulator was overloaded to set the indentation for pretty printing
    std::cout << std::setw(4) << j << std::endl;
  • json和文件的读写

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // read a JSON file
    std::ifstream file("file.json");
    if (!file.is_open()) {
    return;
    }
    json j;
    file >> j;
    file.close();


    // write prettified JSON to another file
    std::ofstream file("pretty.json");
    file << std::setw(4) << j << std::endl;
  • std::vector<>或者std::liststd::uint16_t

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

    # You may leave the iterators for the range [begin, end):
    std::vector<std::uint8_t> v = {'t', 'r', 'u', 'e'};
    json j = json::parse(v);
  • 自定义数据结构struct

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    namespace ns {
    // a simple struct to model a person
    struct person {
    std::string name;
    std::string address;
    int age;
    };
    }

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

    // convert to JSON: copy each value into the JSON object
    json j;
    j["name"] = p.name;
    j["address"] = p.address;
    j["age"] = p.age;

    // ...

    // convert from JSON: copy each value from the JSON object
    ns::person p {
    j["name"].get<std::string>(),
    j["address"].get<std::string>(),
    j["age"].get<int>()
    };

    更方便的方式:to_json()和from_json():

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    using json = nlohmann::json;

    namespace ns {
    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);
    }
    } // namespace ns

    如果key”name”不存在,会抛出异常,可以使用以下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    # 方式1catch异常
    void from_json(const json& j, person& p) {
    try {
    j.at("name").get_to(p.name);
    j.at("address").get_to(p.address);
    j.at("age").get_to(p.age);
    } catch (const std::exception &e)
    {
    std::cout << e.what() << std::endl;
    }
    }

    # 方式2:优先判断
    void from_json(const json& j, person& p) {
    if (j.contains("name")) {
    j.at("name").get_to(p.name);
    }
    if (j.contains("address")) {
    j.at("address").get_to(p.address);
    }
    if (j.contains("age")) {
    j.at("age").get_to(p.age);
    }
    }

    有了以上实现,可以如下使用:

    1
    2
    3
    4
    ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60};
    json j = p;

    ns::person p1 = j.get<ns::person>();
  • class也可以使用to_json()和from_json()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# a.h
using json = nlohmann::json;

class Person {
public:
std::string name;
std::string address;
int age;
friend void to_json(json& j, const Person& p);
friend void from_json(const json& j, Person& p);
};

# a.cpp
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) {
if (j.contains("name")) {
j.at("name").get_to(p.name);
}
if (j.contains("address")) {
j.at("address").get_to(p.address);
}
if (j.contains("age")) {
j.at("age").get_to(p.age);
}
}

# 使用
Person p;
p.name = "pumpkin";
p.address = "any";
p.age = 10;

// conversion: person -> json
json j = p;

// conversion: json -> person
Person p1 = j.get<Person>();

如果类成员是private:

1
2
3
4
5
6
7
8
9
class Person {
private:
std::string name;
std::string address;
int age;
public:
NLOHMANN_DEFINE_TYPE_INTRUSIVE(Person, name, address, age)
};

Binary formats(BSON…)

二进制数据的转换

1
2
3
4
5
6
7
8
9
10
// create a JSON value
json j = R"({"compact": true, "schema": 0})"_json;

// serialize to BSON
std::vector<std::uint8_t> v_bson = json::to_bson(j);

// 0x1B, 0x00, 0x00, 0x00, 0x08, 0x63, 0x6F, ...

// roundtrip
json j_from_bson = json::from_bson(v_bson);
1

1