Json Jsoncpp
文章目录
- Json 介绍
- Jsoncpp 介绍
- Json::Value
- 序列化接口
- 反序列化接口
- 序列化操作
- 反序列化操作
Json 介绍
JSON(JavaScript Object Notation,JavaScript 对象表示法)是一种轻量级的数据交换格式,具有简洁、易读、跨平台等特点,广泛应用于前后端数据传输、配置文件、API 接口等场景。
核心特点:
- 文本格式:基于纯文本,易于人类阅读和编写,也便于机器解析和生成。
- 跨语言兼容:虽然源于 JavaScript,但几乎所有编程语言都有解析和生成 JSON 的库(如 Python 的 json 模块、Java 的 Jackson 等)。
- 数据结构简单:仅支持两种核心结构:
- 键值对集合(类似对象、字典):用
{}
包裹,键值对以:
分隔,格式为{"key": value}
。 - 有序值列表(类似数组):用
[]
包裹,元素以,
分隔,格式为[value1, value2, ...]
。
- 键值对集合(类似对象、字典):用
- 支持的数据类型:字符串(“string”)、数字(整数 / 浮点数,如 123、3.14)、布尔值(true/false)、null、对象、数组。
Json数据格式:
{"name": "Alice","age": 25,"is_student": false,"hobbies": ["reading", "coding"],"address": {"city": "Beijing","street": "Main St"}
}
Jsoncpp 介绍
Jsoncpp 是一个用于 C++ 语言的 JSON 解析库,提供了对 JSON 数据的读写、解析和生成功能,是 C++ 开发中处理 JSON 的常用工具。
核心功能:
- 解析 JSON 字符串 / 文件:将 JSON 格式的文本转换为 C++ 可操作的对象。
- 生成 JSON 字符串 / 文件:将 C++ 中的数据结构转换为 JSON 格式。
- 操作 JSON 数据:支持增删改查 JSON 中的键值对、数组元素等。
主要类和方法
-
Json::Value:最核心的类,用于表示 JSON 中的值(可以是对象、数组、字符串、数字等)。
- 示例:
Json::Value root; root["name"] = "Alice";
(创建键值对)
- 示例:
-
Json::FastWriter / Json::StyledWriter:用于将 Json::Value 转换为 JSON 字符串。(这是旧版序列化接口,这里写出来给大家见一见,我们学习使用还是选择新版的)
FastWriter
:生成紧凑的无缩进字符串。StyledWriter
:生成带缩进的易读字符串。
-
Json::Reader:用于解析 JSON 字符串或文件,将其转换为 Json::Value 对象。(这是旧版反序列化接口,这里写出来给大家见一见,我们学习使用还是选择新版的)
- 示例:
Json::Reader reader; reader.parse(json_str, root)
;(解析字符串到 root)
- 示例:
Jsoncpp
库主要借助三个类以及其对应的少量成员函数完成序列化和反序列化
Json::Value
我们先来看一下 Json
数据对象类的表示(只列举了部分重要的接口):
class Json::Value {// 赋值运算符重载:将另一个Value对象的值赋给当前对象Value &operator=(const Value &other);// 键值对操作:通过字符串键获取/设置值// 示例:val["name"] = "xx"; (设置)或 std::string name = val["name"].asString();(获取)Value& operator[](const std::string& key);Value& operator[](const char* key);// 移除指定键的成员Value removeMember(const char* key);// 数组操作:通过索引获取数组元素(常量版本)// 示例:int firstScore = val["score"][0].asInt();const Value& operator[](ArrayIndex index) const;// 向数组末尾添加元素// 示例:val["score"].append(88);Value& append(const Value& value);// 获取数组元素个数// 示例:int scoreCount = val["score"].size();ArrayIndex size() const;// 类型转换方法std::string asString() const; // 转换为std::string,示例:std::string name = val["name"].asString();const char* asCString() const; // 转换为C风格字符串,示例:const char* name = val["name"].asCString();Int asInt() const; // 转换为整数,示例:int age = val["age"].asInt();float asFloat() const; // 转换为浮点数,示例:float weight = val["weight"].asFloat();bool asBool() const; // 转换为布尔值,示例:bool ok = val["ok"].asBool();
};
Json::Value
是 Jsoncpp 库中最核心的类,如果要将数据对象进行序列化,就需要先存储到Json::Value
对象中。- 如果要将一个
Json
数据串进行反序列化(就是解析完成后),也需要将数据放到Json::Value
对象中。
简单来说,它是 JSON 数据在 C++ 中的 “容器” 和 “操作接口”,所有对 JSON 的创建、修改、访问都通过这个类完成。
序列化接口
// JSON_API 是 Jsoncpp 中用于导出类的宏(跨平台兼容)
// StreamWriter 是一个纯虚基类,定义了 JSON 写入流的接口
class JSON_API StreamWriter {
public:// 纯虚函数:将 JSON 数据(root)写入输出流(sout)// 返回值:写入的字符数(成功)或负数(失败)virtual int write(Value const& root, std::ostream* sout) = 0;// 虚析构函数(基类通常需要定义,确保派生类析构正确)virtual ~StreamWriter() = default;
};// StreamWriterBuilder 是 StreamWriter 的工厂类
// 继承自 StreamWriter::Factory(工厂接口)
class JSON_API StreamWriterBuilder : public StreamWriter::Factory {
public:// 工厂方法:创建并返回一个 StreamWriter 实例// 用于将 Json::Value 转换为 JSON 字符串并写入流virtual StreamWriter* newStreamWriter() const;// 虚析构函数virtual ~StreamWriterBuilder() = default;
};
反序列化接口
// JSON_API 宏导出宏,用于跨平台动态链接
// CharReader 是纯虚基类,定义了解析JSON字符串的接口
class JSON_API CharReader {
public:// 纯虚函数:解析JSON字符串并填充到Value对象// 参数:// beginDoc - JSON字符串的起始地址// endDoc - JSON字符串的结束地址(指向最后一个字符的下一位)// root - 输出参数,解析后的JSON数据将存储到该Value对象// errs - 输出参数,解析错误信息(若解析失败)// 返回值:true表示解析成功,false表示失败virtual bool parse(char const* beginDoc, char const* endDoc,Value* root, std::string* errs) = 0;// 虚析构函数,确保派生类析构函数能正确调用virtual ~CharReader() = default;
};// CharReaderBuilder 是CharReader的工厂类
// 继承自CharReader::Factory(工厂接口)
class JSON_API CharReaderBuilder : public CharReader::Factory {
public:// 工厂方法:创建并返回一个CharReader实例// 用于解析JSON字符串为Json::Value对象virtual CharReader* newCharReader() const;// 虚析构函数virtual ~CharReaderBuilder() = default;
};
序列化操作
前面已经介绍过接口了,所以这里直接演示使用方式:
#include <iostream>
#include <string>
#include <memory>
#include <sstream>
#include <jsoncpp/json/json.h>
using namespace std;// 实现数据的序列化
void serialize(const Json::Value& value, string& output)
{std::stringstream ss;// 先实例化一个工厂类Json::StreamWriterBuilder writer;// 通过工厂类创建一个流写入器std::unique_ptr<Json::StreamWriter> jsonWriter(writer.newStreamWriter());// 将数据写入到字符串流中jsonWriter->write(value, &ss);// 获取字符串流中的内容output = ss.str();
}int main()
{std::string name = "小明";int age = 18;std::string sex = "男";double score[3] = {63, 78.5, 87};// 创建一个Json对象Json::Value fav;fav["书籍"] = "三国演义";fav["运动"] = "篮球";fav["音乐"] = "探窗";Json::Value student;student["姓名"] = name;student["年龄"] = age;student["性别"] = sex;student["成绩"] = Json::arrayValue; // 创建一个数组for (int i = 0; i < 3; ++i) {student["成绩"].append(score[i]); // 向数组中添加元素}student["爱好"] = fav;// 序列化Json对象std::string output;serialize(student, output);std::cout << "Serialized JSON: \n" << output << std::endl;return 0;
}
反序列化操作
#include <iostream>
#include <string>
#include <memory>
#include <sstream>
#include <jsoncpp/json/json.h>
using namespace std;// 实现数据的反序列化
void unserialize(const std::string& input, Json::Value& value)
{// 实例化工厂类Json::CharReaderBuilder readerBuilder;// 创建解析器std::unique_ptr<Json::CharReader> jsonReader(readerBuilder.newCharReader());// 直接使用input解析,无需经过stringstream中转std::string errs;if (!jsonReader->parse(input.c_str(), input.c_str() + input.size(), &value, &errs)) {std::cerr << "Failed to parse JSON: " << errs << std::endl;}
}int main()
{std::string input = R"({"姓名": "小明","年龄": 18,"性别": "男","成绩": [63, 78.5, 87],"爱好": {"书籍": "三国演义","运动": "篮球","音乐": "探窗"}})";Json::Value student;// 反序列化Json字符串unserialize(input, student);// 输出各个字段std::cout << "姓名: " << student["姓名"].asString() << std::endl;std::cout << "年龄: " << student["年龄"].asInt() << std::endl;std::cout << "性别: " << student["性别"].asString() << std::endl;std::cout << "成绩: ";for (Json::ArrayIndex i = 0; i < student["成绩"].size(); ++i) { // 更规范的数组遍历方式std::cout << student["成绩"][i].asDouble() << " ";}std::cout << std::endl;std::cout << "爱好: \n";std::cout << " 书籍: " << student["爱好"]["书籍"].asString() << std::endl;std::cout << " 运动: " << student["爱好"]["运动"].asString() << std::endl;std::cout << " 音乐: " << student["爱好"]["音乐"].asString() << std::endl;return 0;
}