6.2. JsonCpp

JsonCpp 是常用的 C++ JSON 解析库。

6.2.1. 安装

# Ubuntu
sudo apt install libjsoncpp-dev

# macOS
brew install jsoncpp

# 编译
g++ -ljsoncpp program.cpp

6.2.2. 解析 JSON

#include <json/json.h>
#include <fstream>

// 从字符串解析
void parse_from_string() {
    std::string json_str = R"({
        "name": "John",
        "age": 30,
        "active": true,
        "scores": [90, 85, 92]
    })";
    
    Json::Value root;
    Json::CharReaderBuilder builder;
    std::string errors;
    std::istringstream stream(json_str);
    
    if (Json::parseFromStream(builder, stream, &root, &errors)) {
        std::string name = root["name"].asString();
        int age = root["age"].asInt();
        bool active = root["active"].asBool();
        
        for (const auto& score : root["scores"]) {
            std::cout << score.asInt() << "\n";
        }
    }
}

// 从文件解析
void parse_from_file() {
    std::ifstream file("data.json");
    Json::Value root;
    file >> root;
    
    // 使用 root...
}

6.2.3. 创建 JSON

#include <json/json.h>

Json::Value create_json() {
    Json::Value root;
    
    // 基本类型
    root["name"] = "John";
    root["age"] = 30;
    root["active"] = true;
    root["salary"] = 50000.50;
    root["nullable"] = Json::nullValue;
    
    // 数组
    Json::Value scores(Json::arrayValue);
    scores.append(90);
    scores.append(85);
    scores.append(92);
    root["scores"] = scores;
    
    // 嵌套对象
    Json::Value address;
    address["city"] = "New York";
    address["zip"] = "10001";
    root["address"] = address;
    
    return root;
}

6.2.4. 输出 JSON

void output_json(const Json::Value& root) {
    // 紧凑格式
    Json::FastWriter fast_writer;
    std::string compact = fast_writer.write(root);
    
    // 格式化输出
    Json::StyledWriter styled_writer;
    std::string pretty = styled_writer.write(root);
    
    // 使用 StreamWriter (推荐)
    Json::StreamWriterBuilder builder;
    builder["indentation"] = "  ";
    std::string output = Json::writeString(builder, root);
    
    // 写入文件
    std::ofstream file("output.json");
    file << root;
}

6.2.5. 访问值

void access_values(const Json::Value& root) {
    // 安全访问(带默认值)
    std::string name = root.get("name", "unknown").asString();
    int age = root.get("age", 0).asInt();
    
    // 检查存在性
    if (root.isMember("email")) {
        std::string email = root["email"].asString();
    }
    
    // 检查类型
    if (root["age"].isInt()) {
        int age = root["age"].asInt();
    }
    
    // 遍历对象
    for (const auto& key : root.getMemberNames()) {
        std::cout << key << ": " << root[key] << "\n";
    }
    
    // 遍历数组
    for (Json::ArrayIndex i = 0; i < root["scores"].size(); ++i) {
        std::cout << root["scores"][i].asInt() << "\n";
    }
}

6.2.6. 错误处理

bool safe_parse(const std::string& json_str, Json::Value& root) {
    Json::CharReaderBuilder builder;
    std::string errors;
    std::istringstream stream(json_str);
    
    if (!Json::parseFromStream(builder, stream, &root, &errors)) {
        std::cerr << "Parse error: " << errors << "\n";
        return false;
    }
    return true;
}

6.2.7. 替代库:nlohmann/json

nlohmann/json 是现代 C++ 风格的 JSON 库,更易用。

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

void nlohmann_example() {
    // 解析
    json j = json::parse(R"({"name": "John", "age": 30})");
    
    // 访问
    std::string name = j["name"];
    int age = j["age"];
    
    // 创建
    json j2 = {
        {"name", "Jane"},
        {"age", 25},
        {"scores", {90, 85, 92}}
    };
    
    // 序列化
    std::string output = j2.dump(2);  // 缩进 2 空格
    
    // 迭代
    for (auto& [key, value] : j.items()) {
        std::cout << key << ": " << value << "\n";
    }
}

小技巧

JSON 库选择:

  • JsonCpp: 稳定成熟,广泛使用

  • nlohmann/json: 现代 C++,API 更友好

  • RapidJSON: 高性能,适合大文件

  • simdjson: 极高性能,使用 SIMD