【项目组件】第三方库——Jsoncpp

目录

Json数据格式

认识Json数据格式

Json数据类型分类

Jsoncpp库

Json::Value类

StreamWriter类

CharReader类

工厂类

Jsoncpp使用流程

Json序列化

Json反序列化


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库实现序列化,有着固定的流程:

  1. 将需要进行序列化的数据,存储在Json::Value对象中
  2. 实例化一个StreamWriterBuilder工厂类对象
  3. 通过StreamWriterBuilder工厂类对象生产一个StreamWriter对象
  4. 使用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库实现反序列化,有着固定的流程:

  1. 实例化一个CharReaderBuilder工厂类对象
  2. 使用CharReaderBuilder工厂类生产一个CharReader对象
  3. 定义一个Json::Value对象存储解析后的数据
  4. 使用CharReader对象进行json格式字符串str的反序列化
  5. 逐个元素访问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;
}
相关推荐
Winston Wood2 分钟前
Linux中火焰图和eBPF的关系
android·linux·运维·服务器·性能优化
柳鲲鹏34 分钟前
编译OpenCV的速度,家里和公司的电脑相差很大
服务器
Ven%1 小时前
深度学习速通系列:dify快速搭建
linux·运维·服务器·python·自然语言处理·centos·dify
无敌岩雀1 小时前
C++设计模式行为模式———迭代器模式
c++·设计模式·迭代器模式
Narutolxy1 小时前
高效管理 SSH 免密码登录:多客户端与多服务器实践指南20241118
服务器·ssh
solomonzw2 小时前
举例矢量路由协议-RIP
运维·服务器·网络·华为·智能路由器·github
西北大程序猿3 小时前
C++ ──── set和map的模拟实现
开发语言·数据结构·c++
sc写算法3 小时前
C++ 类型转换
开发语言·c++·类型转换
:6424 小时前
Collecting package metadata (current_repodata.json): ...working... done
json