文章目錄
- 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;
}