尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

Asio11-Json

Asio11-Json
📅 发布时间:2026/6/19 4:35:21

Asio11-Json

与protobuf区别

我们上节的protobuf可以做序列化,那么我们为什么又要介绍json格式呢?

原因是,protobuf将信息转化成了二进制的格式,虽然速度快,效率高,可读性却不好。而采用json必然会导致转换效率低,好处是可读性好,也更简单。

一般情况下,protobuf常用在后端个服务器之间通信,而json用在客户端和服务器之间的通信。

nlohmannjson 以及 jsoncpp

nlohmannjson

优点

  • 仅头文件(Header-only): 只需包含一个头文件 #include <nlohmann/json.hpp> 即可使用,无需编译库文件,极易集成。
  • 直观的语法: 其 API 设计非常人性化,与使用标准容器(如 std::map, std::vector)的体验类似。
  • 强大的类型转换: 自动在 JSON 类型和 C++ 类型之间进行转换,无需手动解析。
  • 现代 C++: 充分利用 C++11/14/17/20 的特性,如移动语义、异常等。
  • 严谨: 有严格的测试保障,代码质量高。

用法

创建json对象
#include <iostream>
#include "nlohmann/json.hpp" // 或者 <nlohmann/json.hpp>,取决于你的路径
// 为了方便,通常使用这个命名空间
using json = nlohmann::json;// 1. 创建空对象
json j;// 2. 使用初始化列表(最常用、最直观的方式)
json j_object = {{"pi", 3.141},{"happy", true},{"name", "Niels"},{"nothing", nullptr},{"answer", {{"everything", 42}}},{"list", {1, 0, 2}},{"object", {{"currency", "USD"},{"value", 42.99}}}
};// 3. 像标准容器一样操作
j["new_key"] = "new_value"; // 添加字符串
j["another_list"] = { 1, 2, 3 }; // 添加数组
解析字符串
// 从字符串解析
std::string json_string = R"({"name": "Alice","age": 30,"courses": ["Math", "Physics"]}
)";// 方法 1:使用 json::parse()
json j_from_string = json::parse(json_string);// 方法 2:从文件解析(C++17 以上)
// #include <fstream>
std::ifstream f("example.json");
json j_from_file = json::parse(f);
生成字符串
json j = {{"name", "Bob"}, {"grades", {85, 90, 78}}};// 生成紧凑的字符串
std::string compact_string = j.dump();
// 输出: {"grades":[85,90,78],"name":"Bob"}// 生成格式化的字符串(美化输出,带缩进)
std::string pretty_string = j.dump(4); // 参数是缩进空格数
// 输出:
// {
//     "grades": [
//         85,
//         90,
//         78
//     ],
//     "name": "Bob"
// }std::cout << pretty_string << std::endl;
修改
json j = {{"name", "Charlie"},{"age", 25},{"hobbies", {"reading", "gaming", "coding"}},{"address", {{"city", "Shanghai"},{"zip", "200000"}}}
};// 1. 使用键访问(像 std::map)
std::string name = j["name"]; // "Charlie"
int age = j["age"]; // 25// 2. 访问嵌套对象
std::string city = j["address"]["city"]; // "Shanghai"// 3. 访问数组(像 std::vector)
std::string first_hobby = j["hobbies"][0]; // "reading"// 4. 修改值
j["age"] = 26;
j["address"]["city"] = "Beijing";
j["hobbies"].push_back("hiking"); // 向数组添加新元素// 5. 检查键是否存在
if (j.contains("address")) { // C++20 风格,推荐// ... 
}
// 或者使用 find()
if (j.find("address") != j.end()) {// ...
}// 6. 异常处理:如果键不存在,使用 at() 会抛出异常
try {auto value = j.at("nonexistent_key");
} catch (json::out_of_range& e) {std::cout << "Key not found: " << e.what() << std::endl;
}
类型转换
// 1. 显式转换(推荐,更安全)
auto j = json::parse(R"({"number": 42, "text": "hello"})");int number = j["number"].get<int>();
std::string text = j["text"].get<std::string>();// 2. 隐式转换(方便,但可能不直观)
int number_implicit = j["number"];
std::string text_implicit = j["text"];// 3. 转换整个对象为 C++ STL 容器/结构
std::vector<int> vec = j["list"].get<std::vector<int>>();
std::map<std::string, int> map = j["object"].get<std::map<std::string, int>>();
迭代
json j = {{"one", 1}, {"two", 2}, {"three", 3}};// 迭代对象(键值对)
for (auto& [key, value] : j.items()) {std::cout << key << " : " << value << std::endl;
}// 迭代数组
json j_array = {1, 2, 3, 4, 5};
for (auto& element : j_array) {std::cout << element << ' ';
}
自定义转换
struct Person {std::string name;int age;std::vector<std::string> hobbies;
};// 告诉 nlohmann/json 如何转换你的类型
namespace nlohmann {template <>struct adl_serializer<Person> {static void to_json(json& j, const Person& p) {j = json{{"name", p.name}, {"age", p.age}, {"hobbies", p.hobbies}};}static void from_json(const json& j, Person& p) {j.at("name").get_to(p.name);j.at("age").get_to(p.age);j.at("hobbies").get_to(p.hobbies);}};
}// 使用
Person alice {"Alice", 30, {"chess", "art"}};// 自动将 Person 转换为 json
json j = alice;
std::cout << j.dump(4) << std::endl;// 自动从 json 解析为 Person
std::string json_str = R"({"name": "Bob", "age": 25, "hobbies": ["skiing"]})";
auto j2 = json::parse(json_str);
Person bob = j2.get<Person>();

jsoncpp

优点

速度要比nlohmannjson快,同时很稳定,企业常用。

用法

简单使用
#include <iostream>
#include <json/json.h>
#include <json/value.h>
#include <json/reader.h>
int main()
{Json::Value root;root["id"] = 1001;root["data"] = "hello world";std::string request = root.toStyledString();std::cout << "request is " << request << std::endl;Json::Value root2;Json::Reader reader;reader.parse(request, root2);std::cout << "msg id is " << root2["id"] << " msg is " << root2["data"] << std::endl;
}
创建json对象
#include <iostream>
#include "json/json.h" // 或者 <json/json.h>
// jsoncpp 的所有内容都在 Json 命名空间下
using namespace Json;
解析 JSON 字符串(反序列化)
std::string jsonString = R"({"name": "Alice","age": 30,"courses": ["Math", "Physics"]}
)";// 使用 CharReader 和 CharReaderBuilder
Json::CharReaderBuilder builder;
Json::CharReader* reader = builder.newCharReader();Json::Value root; // 核心类,代表一个 JSON 值(对象、数组、字符串等)
std::string errors;bool parsingSuccessful = reader->parse(jsonString.c_str(),jsonString.c_str() + jsonString.size(),&root,&errors
);delete reader; // 记得释放 readerif (!parsingSuccessful) {std::cout << "Failed to parse JSON: " << errors << std::endl;return 1;
}// 从文件解析 (更简单,推荐)
Json::Value rootFromFile;
std::ifstream ifs("data.json");
ifs >> rootFromFile; // 使用 >> 操作符直接读入
生成 JSON 字符串(序列化)
Json::Value root;
root["name"] = "Bob";
root["age"] = 25;
root["courses"].append("Math"); // 使用 append 向数组添加元素
root["courses"].append("Physics");// 方法 1:紧凑输出
Json::StreamWriterBuilder writerBuilder;
writerBuilder.settings_["indentation"] = ""; // 无缩进
std::string jsonOutput = Json::writeString(writerBuilder, root);
// 输出: {"age":25,"courses":["Math","Physics"],"name":"Bob"}// 方法 2:美化输出(带缩进)
writerBuilder.settings_["indentation"] = "  "; // 两个空格缩进
std::string prettyOutput = Json::writeString(writerBuilder, root);
std::cout << prettyOutput << std::endl;// 方法 3:直接输出到流
Json::StyledStreamWriter writer; // 一个现成的美化输出写入器
writer.write(std::cout, root);
访问和修改数据
Json::Value j;
j["name"] = "Charlie";
j["age"] = 25;
j["hobbies"].append("reading");
j["hobbies"].append("gaming");
j["address"]["city"] = "Shanghai";
j["address"]["zip"] = "200000";// 1. 使用键访问
std::string name = j["name"].asString(); // 必须显式转换
int age = j["age"].asInt();// 2. 访问嵌套对象
std::string city = j["address"]["city"].asString();// 3. 访问数组
// 先检查是否是数组
if (j["hobbies"].isArray()) {for (int i = 0; i < j["hobbies"].size(); ++i) {std::cout << j["hobbies"][i].asString() << std::endl;}// 或者使用迭代器for (const auto& hobby : j["hobbies"]) {std::cout << hobby.asString() << std::endl;}
}// 4. 修改值
j["age"] = 26;
j["address"]["city"] = "Beijing";// 5. 检查键是否存在和类型
// 检查键是否存在
if (j.isMember("address")) {// 检查类型if (j["address"].isObject()) {// ...}
}
if (j["age"].isInt()) {// ...
}// 6. 获取带有默认值的值
int age_with_default = j.get("age", 0).asInt(); // 如果 "age" 不存在,返回 0
std::string country = j.get("country", "China").asString(); // 默认值 "China"
类型转换方法

你必须根据 JSON 值的实际类型调用正确的 asXxx() 方法,否则会抛出异常或返回默认值。

  • asString()
  • asInt(), asUInt()
  • asInt64(), asUInt64()
  • asFloat(), asDouble()
  • asBool()

最佳实践:先检查,再获取

Json::Value value = ...;
if (value.isString()) {std::string s = value.asString();
} else if (value.isInt()) {int i = value.asInt();
} // ... 其他类型
迭代
Json::Value j = ...; // 某个 JSON 对象// 迭代对象的键
Json::Value::Members keys = j.getMemberNames();
for (const auto& key : keys) {std::cout << "Key: " << key << ", Value: " << j[key] << std::endl;
}// 或者直接迭代(C++11 风格)
for (auto it = j.begin(); it != j.end(); ++it) {std::cout << "Key: " << it.name() << ", Value: " << *it << std::endl;
}

相关新闻

  • 基于springboot在线课程管理系统的设计与实现毕业论文+PPT(附源代码+演示视频)
  • 为什么 Web 项目,也应该按 RN 的性能标准来设计
  • hot100-50前缀树

最新新闻

  • PS 怎么删除背景色变成透明?4 种实操方法 + 导出透明 PNG 全流程
  • LDO线性稳压器核心参数解析与TC2054/55/2186选型实战指南
  • 2026年比较好的黄山化粪池管道疏通/附近管道疏通/黄山管道疏通专业公司推荐 - 品牌宣传支持者
  • 2026年诚信的四川冷链运输包装/成都纸塑包装/四川包装/成都水果包装长期合作厂家推荐 - 行业平台推荐
  • 【流形学习多模态语言变量分析基础】王阳明代数讲义之解释深度幻觉
  • 基于深度学习的YOLOv8的微表情识别 表情检测 微表情识别

日新闻

  • 5分钟掌握Python进化算法:Geatpy高性能优化工具完全指南
  • Microchip 24AA044 EEPROM选型与应用全指南:从参数解析到实战编程
  • 华为的鸿蒙到底有多牛?为什么称作遥遥领先?

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号