Featured image of post C++ nlohmann json库快速使用

C++ nlohmann json库快速使用

C++ nlohmann/json 库是一个非常易用,高性能的 json 库

前言

C++ nlohmann/json 库是一个非常易用,高性能的 json 库。

CMake FetchContent方式集成

1
2
3
4
5
6
include(FetchContent)  
FetchContent_Declare(json  
        URL https://github.com/nlohmann/json/releases/download/v3.11.3/json.tar.xz)  
FetchContent_MakeAvailable(json)  
  
target_link_libraries(json_demo PRIVATE nlohmann_json::nlohmann_json)

快速使用

包含头文件以及声明命名空间别名:

1
2
#include <nlohmann/json.hpp>
using json = nlohmann::json;

解析json

从文件读取解析

1
2
3
4
5
6
7
8
// method 1
std::ifstream f("example.json");
json data = json::parse(f);

// method 2
std::ifstream i("file.json");
json j;
i >> j;

从字符串读取解析

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Using (raw) string literals and json::parse
json ex1 = json::parse(R"(
  {
    "pi": 3.141,
    "happy": true
  }
)");

// Using user-defined (raw) string literals
using namespace nlohmann::literals;
json ex2 = R"(
  {
    "pi": 3.141,
    "happy": true
  }
)"_json;

// Using initializer lists
json ex3 = {
  {"happy", true},
  {"pi", 3.141},
};

遍历

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// special iterator member functions for objects
for (json::iterator it = o.begin(); it != o.end(); ++it) {
  std::cout << it.key() << " : " << it.value() << "\n";
}

// the same code as range for
for (auto& el : o.items()) {
  std::cout << el.key() << " : " << el.value() << "\n";
}

// even easier with structured bindings (C++17)
for (auto& [key, value] : o.items()) {
  std::cout << key << " : " << value << "\n";
}

查找 Key

1
2
3
4
5
if (j.contains("key")) {
}

if (j.find("foo") != o.end()) {
}

读取 key

1
2
3
4
5
6
7
8
auto value = j["key"];
auto value = j.at("key");
std::string value = j["key"].template get<std::string>();

// C++17 
using namespace std::literals;
// 如果key不存在,则返回默认值0
int v_integer = j.value("integer"sv, 0); 

删除 key

1
2
// delete an entry
o.erase("foo");

注意:数组可能无法删除单个元素

写入 json 文件

1
2
std::ofstream o("pretty.json");
o << std::setw(4) << j << std::endl;

序列化设置缩进

1
2
// 按照四个空格缩进打印json
std::cout << j.dump(4) << std::endl;

任意类型转换

 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
using json = nlohmann::json;

namespace ns {
  struct person {
        std::string name;
        std::string address;
        int age;
    };
  
  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

// create a person
ns::person p {"Ned Flanders", "744 Evergreen Terrace", 60};

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

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

// conversion: json -> person
auto p2 = j.template get<ns::person>();

通过实现to_json()from_json()完成 json 与结构体的映射关系。

[!warning]

  • 使用template get<your_type>()时,必须保证是可以默认构造的。
  • from_json 中,使用 at() 来访问对象的值,而不是 operator[] 。如果某个键不存在, at 会抛出一个可以处理的异常,而 operator[] 则会表现出未定义的行为。

如果想要将 JSON 对象用作序列化或想要将成员变量名称用作该对象的键。可以使用宏简化操作(自动实现to_json()from_json()):

  • NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(name, member1, member2, ...):在类/结构体的命名空间内进行定义。
  • NLOHMANN_DEFINE_TYPE_INTRUSIVE(name, member1, member2, ...):在类/结构内部定义的标识符,用于创建代码。这个宏还可以访问私有成员。

命名空间中使用:

1
2
3
4
5
6
7
8
namespace ns {
  struct person {
        std::string name;
        std::string address;
        int age;
    };
  NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person, name, address, age)
}

使用私有成员:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
namespace ns {
  class address {
    private:
      std::string street;
      int housenumber;
      int postcode;

    public:
      NLOHMANN_DEFINE_TYPE_INTRUSIVE(address, street, housenumber, postcode)
  };
}

总结

以上就是在使用 json 库时的常用场景。

https://github.com/nlohmann/json

https://github.com/nlohmann/json/tree/develop/docs/examples

Licensed under CC BY-NC-SA 4.0
最后更新于 Sep 07, 2024 16:07 +0800