Skip to content

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 宏是序列化自定义类型的最简方式。

系统学习 C++ 生态,深入底层架构