目录
Json数据格式
认识Json数据格式
Json 是⼀种数据交换格式,它采用完全独立于编程语⾔的⽂本格式来存储和表示数据。
例如: 我们想表示⼀个同学的学⽣信息
C代码表示:
cpp
char *name = "xx"; //学生姓名
int age = 18; //学生年龄
float score[3] = {88.5, 99, 58}; //学生成绩
Json表示:
cpp
{
"姓名" : "xx",
"年龄" : 18,
"成绩" : [88.5, 99, 58]
}
[
{"姓名":"⼩明", "年龄":18, "成绩":[23, 65, 78]},
{"姓名":"⼩红", "年龄":19, "成绩":[88, 95, 78]}
]
Json数据类型分类
Json的数据类型包括对象,数组,字符串,数字等
- 对象:使⽤花括号 {} 括起来的表示⼀个对象
- 数组:使⽤中括号 [] 括起来的表示⼀个数组
- 字串:使⽤常规双引号 "" 括起来的表示⼀个字符串
- 数字:包括整形和浮点型,直接使⽤
注意:Json的类型是可以嵌套使用的!
其中Json数据格式是以":"为分割的kv结构,":"左边的是key,":"右边的是value
嵌套对象
cpp
{
"name": "John Doe",
"age": 30,
"address": {
"street": "123 Main St",
"city": "Anytown",
"state": "CA",
"zipcode": "12345"
},
"phoneNumbers": {
"home": "555-1234",
"work": "555-5678"
}
}
- 上述Json中,最外层的{}为一个对象,对象中属性包含name、age、address、phoneNumbers
- address既是外层{}的属性之一,它本身也是一个对象,该对象中属性包含street、city、state、zipcode
- phoneNumbers既是外层{}的属性之一,它本身也是一个对象,该对象中属性包含home、work
嵌套数组
cpp
{
"name": "Jane Smith",
"age": 28,
"children": [
{
"name": "Emily",
"age": 6
},
{
"name": "Michael",
"age": 4
}
],
"hobbies": ["reading", "hiking", "coding"]
}
- 上述Json串中,最外层{}是一个对象,它包含的属性是name、age、children、hobbies
- children是一个对象数组,数组中包含两个对象,这两个对象的属性是name和age
- hobbies是一个字符串数组,数组中包含三个串
复杂嵌套
cpp
{
"store": {
"book": [
{
"category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95
},
{
"category": "fiction",
"author": "Evelyn Waugh",
"title": "Sword of Honour",
"price": 12.99
}
],
"bicycle": {
"color": "red",
"price": 19.95
}
}
}
- 最外层{}是一个对象,该对象只包含一个属性为store
- store也是一个对象,该对象中包含两个属性是book和bicycle
- book是一个对象数组,book中存储着两个对象,这两个对象的属性是category、author、title、price
- bicycle是一个对象,该对象有两个属性是color和price
Jsoncpp库
Jsoncpp 库主要是用于实现 Json 格式数据的序列化和反序列化,它实现了将多个数据对象组织成
为 J son 格式字符串,以及将 Json 格式字符串解析得到多个数据对象的功能
Jsoncpp中主要的类有三个:
- Json::Value
- StreamWriter
- CharReader
除此之外,Jsoncpp中还包含两个工厂类用于实例化StreamWriter和CharReader对象
- StreamWriterBuilder
- CharReaderBuilder
Json::Value类
Json::Value类是Jsoncpp库中的一个核心类,它用于表示Json数据的任意类型。
非数组类型的操作
cpp
Value &operator=(const Value &other);
operator=接口一般与下面的[]接口搭配使用
通过Json的Key访问值的接口:
cpp
Value& operator[](const std::string& key);//简单的⽅式完成 val["name"] = "xx";
Value& operator[](const char* key);
通过上面这两个接口,一般可以完成对值的设置,如下:
cpp
Json::Value stu;
stu["name"] = "张三";//把key为name的值设置为张三
注意:上述接口返回的是Value对象,若我们需要打印该对象,那么需要先转化为字符串
将Value对象转化为其他类型的接口:
cpp
std::string asString() const;//转string
const char* asCString() const;//转char*
Int asInt() const;//转int
float asFloat() const;//转float
bool asBool() const;//转bool
以转化为string对象为例,其他都一样
cpp
Json::Value root;
root["name"] = "张三";
std::string str = root["name"].asString();
//str存储的是张三
删除Value对象中的某个key的接口:
cpp
Value removeMember(const char* key);
如下示例:
cpp
Json::Value root;
root["city"] = "New York";
root.removeMember("city");
数组类型的操作
Jsoncpp中对数组类型的操作与其他类型有些不同
通过Json的Key访问数组的接口与之前访问其他类型时是一样的
插入时有所不同,对于其他类型直接使用operator=即可,对于数组类型需要调用append接口
cpp
Value& append(const Value& value);
如下使用:
cpp
Json::Value root;
root["score"].append(66);
root["score"].append(77);
root["score"].append(88);
//score数组 = [66,77,88]
通过下标访问数组元素:
cpp
const Value& operator[](ArrayIndex index) const;//val["score"][0]
获取数组元素个数:
cpp
ArrayIndex size() const;//获取数组元素个数 val["score"].size();
判断是否存在某个字段
cpp
bool isNull(); //⽤于判断是否存在某个字段
StreamWriter类
该类是专门用于进行序列化操作的
该类中只有一个接口,用于完成序列化:
cpp
virtual int write(Value const& root, std::ostream* sout) = 0;
该结果的功能是将root对象序列化,序列化后的结果保存到sout中
一般sout参数可以传入一个std::stringstream对象,并使用该对象的str接口打印序列化结果
CharReader类
该类是专门用于进行反序列化操作的
该类中只有一个接口,用于完成反序列化
cpp
virtual bool parse(char const* beginDoc, char const* endDoc,
Value* root, std::string* errs) = 0;
该接口会把str字符串通过Json数据格式进行反序列化
beginDoc参数:str字符串的起始位置
endDoc参数:str字符串的结尾
root参数:输出型参数,最终反序列化结果保存在root中
errs参数:parse可能出错,errs保存出错原因
工厂类
创建StreamWriter对象:
cpp
class JSON_API StreamWriterBuilder : public StreamWriter::Factory {
virtual StreamWriter* newStreamWriter() const;
}
创建CharReader对象:
cpp
class JSON_API CharReaderBuilder : public CharReader::Factory {
virtual CharReader* newCharReader() const;
}
Jsoncpp使用流程
Json序列化
使用Jsoncpp库实现序列化,有着固定的流程:
- 将需要进行序列化的数据,存储在Json::Value对象中
- 实例化一个StreamWriterBuilder工厂类对象
- 通过StreamWriterBuilder工厂类对象生产一个StreamWriter对象
- 使用StreamWriter对象,对Json::Value中存储的数据进行序列化
cpp
#include <iostream>
#include <jsoncpp/json/json.h>
#include <memory>
#include <sstream>
int main()
{
// 将需要进行序列化的数据,存储在Json::Value对象中
Json::Value root;
root["姓名"] = "张三";
root["年龄"] = "18";
root["成绩"].append(66);
root["成绩"].append(77);
root["成绩"].append(88);
// 实例化一个StreamWriterBuilder工厂类对象
Json::StreamWriterBuilder Wbuild;
// 通过StreamWriterBuilder工厂类对象生产一个StreamWriter对象
std::unique_ptr<Json::StreamWriter> sw(Wbuild.newStreamWriter());
// 使用StreamWriter对象,对Json::Value中存储的数据进行序列化
std::stringstream ss;
sw->write(root,&ss);
// 打印ss中序列化好的结果
std::cout << ss.str() << std::endl;
return 0;
}
Json反序列化
使用Jsoncpp库实现反序列化,有着固定的流程:
- 实例化一个CharReaderBuilder工厂类对象
- 使用CharReaderBuilder工厂类生产一个CharReader对象
- 定义一个Json::Value对象存储解析后的数据
- 使用CharReader对象进行json格式字符串str的反序列化
- 逐个元素访问Json::Value中的数据
cpp
int main()
{
std::string info = Serialize(); //获取序列化结果,参考前一个代码中的序列化
// 实例化一个CharReaderBuilder工厂类对象
Json::CharReaderBuilder crb;
// 使用CharReaderBuilder工厂类生产一个CharReader对象
std::unique_ptr<Json::CharReader> cr(crb.newCharReader());
// 定义一个Json::Value对象存储解析后的数据
Json::Value root;
// 使用CharReader对象进行json格式字符串str的反序列化
std::string errs;
cr->parse(info.c_str(),info.c_str()+info.size(),&root,&errs);
// 逐个元素访问Json::Value中的数据
std::cout << "姓名: "<< root["姓名"].asString() << std::endl;
std::cout << "年龄: "<< root["年龄"].asString() << std::endl;
std::cout << "成绩: ";
for(int i = 0 ; i < root["成绩"].size() ; ++i)
{
std::cout << root["成绩"][i] << " ";
}
std::cout << std::endl;
return 0;
}