nlohmann/json — JSON 库
nlohmann/json 是 C++ 最流行的 JSON 库,单头文件,API 直观,像操作 Python dict 一样操作 JSON。
安装
bash
# 单头文件(最简单)
# 下载 json.hpp 放到项目中
# https://github.com/nlohmann/json/releases
# vcpkg
vcpkg install nlohmann-json
# CMake
find_package(nlohmann_json REQUIRED)
target_link_libraries(myapp PRIVATE nlohmann_json::nlohmann_json)基本操作
cpp
#include <nlohmann/json.hpp>
using json = nlohmann::json;
// 构造 JSON
json j;
j["name"] = "Alice";
j["age"] = 30;
j["scores"] = {95, 87, 92};
j["address"] = {{"city", "Beijing"}, {"zip", "100000"}};
j["active"] = true;
j["data"] = nullptr;
// 序列化
std::string s = j.dump(); // 紧凑格式
std::string pretty = j.dump(4); // 缩进 4 空格
std::cout << pretty << "\n";
// 反序列化
std::string input = R"({"name":"Bob","age":25})";
json parsed = json::parse(input);
std::cout << parsed["name"] << "\n"; // "Bob"
std::cout << parsed["age"] << "\n"; // 25类型访问
cpp
json j = json::parse(R"({
"name": "Alice",
"age": 30,
"scores": [95, 87, 92],
"active": true
})");
// 获取值(自动类型转换)
std::string name = j["name"];
int age = j["age"].get<int>();
bool active = j.at("active"); // at() 越界抛异常
// 数组访问
for (auto& score : j["scores"]) {
std::cout << score.get<int>() << "\n";
}
// 安全访问(键不存在时返回默认值)
std::string city = j.value("city", "unknown");
// 检查键是否存在
if (j.contains("name")) {
std::cout << j["name"] << "\n";
}
// 类型检查
j["name"].is_string(); // true
j["age"].is_number(); // true
j["scores"].is_array(); // true
j.is_object(); // true自定义类型序列化
cpp
struct Person {
std::string name;
int age;
std::vector<int> scores;
};
// 方式 1:侵入式(在类外定义 to_json/from_json)
void to_json(json& j, const Person& p) {
j = json{
{"name", p.name},
{"age", p.age},
{"scores", p.scores}
};
}
void from_json(const json& j, Person& p) {
j.at("name").get_to(p.name);
j.at("age").get_to(p.age);
j.at("scores").get_to(p.scores);
}
// 使用
Person alice{"Alice", 30, {95, 87, 92}};
json j = alice; // 自动调用 to_json
std::string s = j.dump(2);
Person bob = json::parse(R"({"name":"Bob","age":25,"scores":[80,90]})");
// 方式 2:宏(最简洁,C++14)
#include <nlohmann/json.hpp>
struct Config {
std::string host;
int port;
bool debug;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(Config, host, port, debug)
};
Config cfg{"localhost", 8080, true};
json j = cfg;
Config cfg2 = j;文件读写
cpp
#include <fstream>
// 写入文件
json config = {
{"host", "localhost"},
{"port", 8080},
{"debug", false}
};
std::ofstream out("config.json");
out << std::setw(4) << config; // 格式化写入
// 读取文件
std::ifstream in("config.json");
json loaded;
in >> loaded;
// 或者
json loaded2 = json::parse(std::ifstream("config.json"));高级特性
cpp
// JSON Pointer(RFC 6901)
json j = {{"a", {{"b", {{"c", 42}}}}}};
int val = j["/a/b/c"_json_pointer]; // 42
j["/a/b/d"_json_pointer] = "new";
// JSON Patch(RFC 6902)
json patch = json::parse(R"([
{"op": "replace", "path": "/name", "value": "Bob"},
{"op": "add", "path": "/email", "value": "bob@example.com"}
])");
j.patch_inplace(patch);
// 合并 Patch(RFC 7396)
json base = {{"a", 1}, {"b", 2}};
json merge = {{"b", 3}, {"c", 4}};
base.merge_patch(merge); // {"a":1, "b":3, "c":4}
// 迭代器
for (auto& [key, val] : j.items()) {
std::cout << key << ": " << val << "\n";
}
// 扁平化
json nested = {{"a", {{"b", 1}}}, {"c", 2}};
json flat = nested.flatten(); // {"/a/b": 1, "/c": 2}
json unflat = flat.unflatten();性能优化
cpp
// SAX 解析(流式,低内存)
#include <nlohmann/json.hpp>
struct MySaxHandler : nlohmann::json_sax<json> {
bool key(string_t& val) override {
std::cout << "key: " << val << "\n";
return true;
}
bool number_integer(number_integer_t val) override {
std::cout << "int: " << val << "\n";
return true;
}
// ... 实现其他回调
bool null() override { return true; }
bool boolean(bool val) override { return true; }
bool number_unsigned(number_unsigned_t val) override { return true; }
bool number_float(number_float_t val, const string_t&) override { return true; }
bool string(string_t& val) override { return true; }
bool binary(binary_t& val) override { return true; }
bool start_object(std::size_t) override { return true; }
bool end_object() override { return true; }
bool start_array(std::size_t) override { return true; }
bool end_array() override { return true; }
bool parse_error(std::size_t, const std::string&,
const nlohmann::detail::exception&) override { return false; }
};
MySaxHandler handler;
json::sax_parse(R"({"key": 42})", &handler);
// BSON/MessagePack(二进制格式,更快更小)
json j = {{"name", "Alice"}, {"age", 30}};
auto msgpack = json::to_msgpack(j); // 二进制
auto back = json::from_msgpack(msgpack);关键认知
nlohmann/json 的 API 设计极其直观,但性能不是最优(比 simdjson 慢 5-10x)。对于性能敏感场景,考虑 simdjson 或 rapidjson。NLOHMANN_DEFINE_TYPE_INTRUSIVE 宏是序列化自定义类型的最简方式。