JsonCpp库的使用

news2024/11/13 7:55:35

目录

一、Json数据格式

二、JsonCpp介绍

2.1 Json::Value

2.2 序列化接口

2.3 反序列化接口

三、JsonCpp的使用

3.1 头文件包含

3.2 序列化

3.3 反序列化

四、补充


Json 是⼀种数据交换格式,它采⽤完全独⽴于编程语⾔的⽂本格式来存储和表示数据。

一、Json数据格式

Json 的数据类型包括对象,数组,字符串,数字等。
• 对象:使⽤花括号 { } 括起来的表⽰⼀个对象
• 数组:使⽤中括号 [ ] 括起来的表⽰⼀个数组
• 字符串:使⽤常规双引号 " " 括起来的表示⼀个字符串
• 数字:包括整形和浮点型,直接使用

C语言 代码表示:

char *name = "张三";
int age = 18;
int score[3] = { 100, 110, 96 };

Json 表示:

{
    "姓名" : "张三",
    "年龄" : 18,
    "成绩" : [100, 110, 96],
    "喜欢的人" :{
        "姓名" : "小丽",
        "年龄" : "18",
        "成绩" : [ 110, 112, 110]
    }
}

注意,在Json中,每个对象的各个数据用 , 分割,最后一行数据不需要使用 ,  

二、JsonCpp介绍

上述 Json 只是为我们提供了一种格式,具体的实现还需要每种语言配有对应的框架,这里我们就开始认识一下 JsonCpp ,主要学习其中的三个类即可。

2.1 Json::Value

如果要将数据对象进行序列化,就需要先将对象存储到 Json::Value 对象中
如果要将数据传输后进行反序列化,即解析,会将数据对象放入到 Json::Value 对象中

class Json::Value
{
    Value &operator=(const Value &other); //Value重载了[]和=,因此所有的赋值和获取数据都可以通过 = 
    Value& operator[](const std::string& key); //简单的⽅式完成 val["name"] = "xx";
    Value& operator[](const char* key);
    Value removeMember(const char* key); //移除元素
    const Value& operator[](ArrayIndex index) const; //val["score"][0]
    Value& append(const Value& value); //添加数组元素val["score"].append(88);
    ArrayIndex size() const; //获取数组元素个数 val["score"].size();
    std::string asString() const; //转string string name = val["name"].asString();
    const char* asCString() const; //转char* char *name = val["name"].asCString();
    Int asInt() const; //转int int age = val["age"].asInt();
    float asFloat() const; //转float float weight = val["weight"].asFloat();
    bool asBool() const; //转 bool bool ok = val["ok"].asBool();
};

下面简单认识一下其中的部分成员:

= 运算符重载:Value 重载了[]和=,因此所有的赋值和获取数据都可以通过 = 来赋值

[] 运算符重载:Value 重载了[]和=,因此所有的赋值和获取数据都可以通过 = 来赋值

例:val ["name"] = "张三"

[] 运算符重载:使 Value 中的数组成员可以直接使用下标访问

例: val["score"][0]

append 函数:直接追追加 Value 中的数组成员

例: val["score"].append(89) 如果不使用append,89会覆盖上一个score成员!

size 函数:返回 Value 中的数组成员的数量,方便遍历某成员

2.2 序列化接口

class JSON_API StreamWriter 
{
    virtual int write(Value const& root, std::ostream* sout) = 0;
}
class JSON_API StreamWriterBuilder : public StreamWriter::Factory 
{
    virtual StreamWriter* newStreamWriter() const;
}

重点是 StreamWriter::write() 作为序列化函数,

其中,Json::StreamWriterBuilder 是继承自 Json::StreamWriter 的工厂类,用于生产 Json::StreamWriter 对象

write 写入成功时,会返回一个0,不成功则会返回非0

第一个参数指的是要进行序列化的 Json::Value 对象

第二个参数指的是要写入的输出流

2.3 反序列化接口

class JSON_API CharReader 
{
    virtual bool parse(char const* beginDoc, char const* endDoc, Value* root, std::string* errs) = 0;
}
class JSON_API CharReaderBuilder : public CharReader::Factory 
{
    virtual CharReader* newCharReader() const;
}

重点是 Json::CharReader::parse() 作为反序列化函数,

其中,Json::CharReaderBuilder 是继承自 Json::CharReader 的工厂类,用于生产 Json::CharReader 对象

parse 返回值是布尔类型,若 parse 成功返回 true,反之返回 true

第一个参数是要反序列化数据的起始地址

第二个参数是要反序列化数据的末尾地址

第三个参数是反序列化后数据要写入的 Json::Value 对象,要进行地址传参

第四个参数是报错信息,可以定义一个 std::string 对象进行地址传参

三、JsonCpp的使用

3.1 头文件包含

如果你的环境中已经安装了 Json 库,那么我们只需要 jsoncpp/json/json.h 文件,所以头文件如下

#include <iostream>
#include <string>
#include <jsoncpp/json/json.h>

此外,如果使用 makefile ,还需要连接上 jsoncpp ,这里我将序列化和反序列化的 demo 分成了两个文件,如下:

all:Serialize unSerialize
Serialize:Serialize.cpp
	g++ -o $@ $^ -std=c++11 -ljsoncpp
unSerialize:unSerialize.cpp
	g++ -o $@ $^ -std=c++11 -ljsoncpp
.PHONY:clean
clean:
	rm -rf unSerialize Serialize

3.2 序列化

可以先定义变量存储我们需要传入 Json::Value 的值,然后直接定义一个 Json::Value 的对象,并为对象赋值。

随后需要序列化时不能直接使用 Json::StreamWriter ,而是要先定义一个 Json::StreamWriterBuilder 对象,再创建一个 Json::StreamWriter 对象的指针接收由 Json::StreamWriterBuilder 对象调用其 newStreamWriter() 的返回值。

最后,可以使用 writer 函数,并指定输出流对象。

//数据序列化
void Serialize()
{
    const char* name = "XiaoMing";
    const char*sex = "Man";
    int age = 18;
    int score[3] = { 100, 110, 96 };

    Json::Value student;
    student["Name"] = name;
    student["Sex"] = sex;
    student["Age"] = age;
    student["Score"].append(score[0]);
    student["Score"].append(score[1]);
    student["Score"].append(score[2]);

    //定义工厂类对象
    Json::StreamWriterBuilder swb;
    Json::StreamWriter *sw(swb.newStreamWriter());
    sw->write(student, &std::cout);
    std::cout << std::endl;

    delete sw;
}

int main()
{
    Serialize();
    return 0;
}

同时,还需要释放 Json::StreamWriter 对象的内存,以后会进行进一步优化。 

为了避免内存泄露,可以使用智能指针管理 Json::StreamWriter 对象,同时,为了代码更加简洁,可以对 Serialize() 进一步封装。将要序列化的信息作为传入参数,并使用输出型参数以字符串的方式输出序列化后的信息中,这里要使用到 stringstream 用作数据的缓冲区,用于 Json::Value 格式转换到 std::string 格式。

将序列化后的信息带回到字符串后,可以打印出字符串的信息来查看序列化后的信息。

#include <iostream>
#include <string>
#include <sstream>
#include <memory>
#include <jsoncpp/json/json.h>

//数据序列化
bool Serialize(const Json::Value &val, std::string &body)
{
    //中间缓冲区,将 Json::Value 格式转换为 std::string 格式
    std::stringstream ss;
    //定义工厂类对象
    Json::StreamWriterBuilder swb;
    std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());
    //如果 write 返回值不为零,则错误
    int ret = sw->write(val, &ss);
    if (ret != 0)
    {
        std::cout << "Serialize Error!";
        return false;
    }
    body = ss.str();
    return true;
}

int main()
{
    const char* name = "XiaoMing";
    const char*sex = "Man";
    int age = 18;
    int score[3] = { 100, 110, 96 };

    Json::Value student;
    std::string body;
    student["Name"] = name;
    student["Sex"] = sex;
    student["Age"] = age;
    student["Score"].append(score[0]);
    student["Score"].append(score[1]);
    student["Score"].append(score[2]);
    Serialize(student, body);
    //打印字符串信息
    std::cout << body << std::endl;

    return 0;
}

可以看到序列化的结果是一样的。

3.3 反序列化

反序列化我们直接使用封装,先定义一个工厂类 Json::CharReaderBuilder,然后使用工厂类生成一个 Json::CharReader 对象,调用该对象的类内方法 parse 进行反序列化。

//数据反序列化
bool unSerialize(std::string &body, Json::Value &val)
{
    //定义工厂类
    Json::CharReaderBuilder crb;
    std::unique_ptr<Json::CharReader> cr(crb.newCharReader());
    //错误信息缓冲区
    std::string errs;
    bool ret = cr->parse(body.c_str(), body.c_str() + body.size(), &val, &errs);
    if (ret == false)
    {
       std::cout << "unSerialize Error!";
       return false; 
    }
    return true;
}

在进行测试时,可以直接自定义一个序列化字符串,在 R"()" 的小括号中定义出序列化的信息,然后使用 Json::Value 进行接收并分别打印:

int main()
{
    //序列化数据
    std::string s = R"({"Name":"XiaoHong", "Sex":"Woman", "Age":18})";
    //反序列化后的结果填入 Json::Value 中
    Json::Value stu;
    bool ret = unSerialize(s, stu);
    if (ret == false)
    {
        return -1;
    }
    std::cout << "Name:" << stu["Name"].asString() << " Sex:" << stu["Sex"].asString() << " Age:" << stu["Age"].asString() << std::endl; 
    return 0;
}

同时,在输出时,可以使用字符串 

四、补充

4.1 中文乱码

Json 也可以使用中文,如果你使用中文是乱码的话,如下:

那你可以在定义工厂类对象后添加以下信息:

// 设置 emitUTF8 使其输出原始的 UTF-8 编码而不是转义序列
swb["emitUTF8"] = true;

此时再重新编译,就可以得到不乱码的中文结果:

4.2 demo 源码

源码链接如下,有需要的可以参考 demo 源码:

从零实现JsonRpc框架: CPP项目——从零实现JsonRpc项目博客链接:https://blog.csdn.net/m0_75186846/category_12772639.html - Gitee.comicon-default.png?t=N7T8https://gitee.com/bright-and-sparkling-at-night/JsonRpc/tree/master/demo/jsoncpp

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2102403.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

P01-Java何谓数组

P01-Java何谓数组 一、数组声明创建 1.1 数组声明的语法 与c有所不同 在Java中&#xff0c;数组声明语法 首选语法&#xff1a; //数据类型[] 数组名称; int[] arr;次选&#xff0c;与c类似 //数据类型 数组名称[]; int arr[];1.2 数组创建语法 与c指针有所相似&#xff0…

嵌入式开发与应用按键外部中断实验二

一、实验目的 1. 通过实验掌握中断式键盘控制与设计方法&#xff1b; 2. 熟悉编写中断服务程序; 3. 掌握中断系统相关知识&#xff0c;掌握外部中断应用方法和处理过程&#xff1b; 4. 掌握实验处理器中断处理的软件编程方法&#xff1b; 5. 从按键程序的设计对系统的编程…

Prometheus_0基础_学习笔记

一、基本概念 Prometheus是由golang语言开发的一套开源的监控、报警、时间序列数据库的组合&#xff0c;是一款基于时序数据库的开源监控告警系统。 时间序列数据库&#xff1a;时间序列数据库&#xff08;Time Serires Database , TSDB&#xff09;不同于传统的关系型数据库。…

是缔造AI程序员,还是AI缔造程序员?

随着AIGC&#xff08;如ChatGPT、MidJourney、Claude等&#xff09;大语言模型的涌现&#xff0c;AI辅助编程工具的普及使得程序员的工作方式正在发生深刻变革。AI的迅猛发展&#xff0c;不仅提升了编程效率&#xff0c;也引发了对程序员未来职业前景的深思。我们应当如何在这一…

【归并分而治之】逆序对的应对之策

目录 1.前言2.题目简介3.求解思路为什么要这样做&#xff1f;快在哪&#xff1f;为什么这种方法会想到结合归并排序&#xff1f;如何在一左一右中统计剩下的逆序对个数&#xff1f;固定右边的数&#xff0c;用降序会怎么样&#xff1f;&#xff1f;&#xff1f;思路的本质是巧妙…

【MySQL07】【锁】

文章目录 一、前言二、事务的读写情况1. 写-写情况2. 读-写情况3. 一致性读4. 锁定读2.1 共享锁和独占锁2.2 锁定读的语句 5. 写操作 三、多粒度锁四、表锁和行锁1. 表级锁1.1 表级别的 S锁 和 X锁1.2 表级别的 IS 锁和 IX锁1.3 表级别的 AUTO-INC 锁 2. 行级锁2.1 行级锁的分类…

Qt6+VTK9环境配置

Qt6VTK9环境配置 说明1 Qt6安装2 VTK源码编译2.1 源码下载2.2 工程编译2.3 设置环境变量 3 QtVTK项目构建3.1 使用qmake管理项目3.2 使用cmake管理项目 参考资料 说明 由于想做一点新的东西&#xff0c;需要去探索一些工具&#xff0c;对于VTK之前没有了解过&#xff0c;在进行…

redis缓存和数据库通过延迟双删除实现数据一致性

为了提高查询的效率&#xff0c;我们经常会用到redis缓存&#xff0c;但是使用redis缓存就不可避免缓存一致性的问题。 先删缓存&#xff0c;再更新数据 如果并发查询可能会再删除缓存后&#xff0c;还没有更新数据库的时候&#xff0c;第二个线程读取到旧数据&#xff0c;并…

尚品汇-商品上下架完善(更新ES)、延迟消息(四十四)

目录&#xff1a; &#xff08;1&#xff09;改造商品搜索上下架 &#xff08;2&#xff09;延迟消息 &#xff08;1&#xff09;改造商品搜索上下架 定义商品上下架常量 在rabbit-util模块中导入常量类MqConst。 /*** 商品上下架.*/ public static final String EXCHANGE…

游戏翻译中西班牙语的特点

由于西班牙语丰富的文化多样性和广泛的使用&#xff0c;将游戏翻译成西班牙语带来了独特的机遇和挑战。西班牙语是全球第二大使用语言&#xff0c;包括西班牙、拉丁美洲和美国部分地区在内的各个地区有超过4.6亿母语人士。然而&#xff0c;这些地区的语言和文化差异需要量身定制…

Datawhale X 李宏毅苹果书 AI夏令营-深度学习进阶task1:局部极小值与鞍点,批量和动量

一、临界点和鞍点 在做优化的时候经常会发现&#xff0c;随着参数不断更新&#xff0c;训练的损失不会再下降, 但是我们对这个损失仍然不满意或者有时模型一开始就训练不起来&#xff0c;不管我们怎么更新参数&#xff0c;损失都降不下去。 过去常见的一个猜想是我们优化到某…

GPU环境配置:1.CUDA、Anaconda、Pytorch

一、查看显卡适配CUDA型号 查看自己电脑的显卡版本&#xff1a; 在 Windows 设置中查看显卡型号&#xff1a;使用 Windows I 快捷键打开「设置」&#xff0c;依次点击「系统」-「屏幕」和「高级显示器设置」&#xff0c;在「显示器 1」旁边就可以看到显卡名称。 右键点菜单图标…

自动生成对话视频!如何使用Captions的AI视频生成与编辑API工具?

Captions公司最近发布了一套AI驱动的视频生成和编辑API工具&#xff0c;为创作者和开发者提供了一个强大的视频创作生态系统。这个系统包含AI Creator、AI Twin、AI Edit、和AI Translate四大核心功能&#xff0c;每个工具都针对不同的创作需求进行优化。下面我们就一起来详细测…

宏定义## 的使用

宏定义## 的使用 C语言中宏定义## 的使用 宏定义## 的使用 #define LV_color(x,y,z) x##y##z 文章目录 宏定义## 的使用宏定义## 的使用 宏定义## 的使用 #include<stdio.h> #include<stdlib.h>#define LV_color(x,y,z) x##y##z int main() {printf("LV_col…

SaaS行业|深入探讨五个联盟营销平台

随着数字时代的飞速发展&#xff0c;SaaS&#xff08;Software as a Service&#xff0c;软件即服务&#xff09;行业正以前所未有的速度崛起&#xff0c;成为推动全球商业变革的重要力量。本文将深入探索分析SaaS行业的五个营销联盟营销平台。 1. PartnerShare&#xff1a;Saa…

保姆级Vue项目安装配置步骤(包含vue-cli脚手架环境配置、Vue项目创建、运行)

文章目录 1. Vue-cli脚手架安装2. Vue项目创建(使用图形化界面创建步骤&#xff09;3. Vue项目-运行4. Vue项目-配置端口 此教程摘选自我的笔记&#xff1a;黑马JavaWeb开发笔记08——(保姆级Vue项目全部安装配置步骤)Vue-cli脚手架安装、NodeJS环境搭建、Vue项目的创建、运行、…

zdppy+vue3+onlyoffice文档管理系统实战 20240903 上课笔记 登录功能完成

接下来 1、注销功能&#xff1a;点击注销按钮&#xff0c;清除登录信息跳转到登录页面2、token过期 注销功能 useUser.js import storage from "../../g/storage.js"; import {useRouter} from "vue-router"; import {message} from "ant-design-…

【vue Lottie】lottie在vue项目中的使用心得

✨减少依赖体积 ●能用原生实现的动效&#xff0c;就不要切Lottie&#xff0c;提前做好切分 ●使用的时候&#xff0c;不要一股脑的复制粘贴过来&#xff0c;而是应该进行如下步骤的清洗 ○合并同样的图片依赖素材&#xff0c;减小依赖图片的大小 ○一些很大的背景图片&…

比亚迪夏亮相,枪口究竟对准了谁?

文/王俣祺 导语&#xff1a;比亚迪的MPV终于要来了&#xff0c;比亚迪夏在成都车展上正式亮相&#xff0c;据说售价会在30万级别&#xff0c;如果是这一几个区间&#xff0c;可以说是把矛头直接指向了腾势D9。作为比亚迪“宗亲”的腾势D9匆忙表示“大哥别开枪&#xff0c;自己人…

多晶透明陶瓷市场发展现状和前景:未来几年年复合增长率CAGR为15.5%

多晶透明陶瓷是一种新型先进功能材料&#xff0c;它具有独特的机械性能和透射性能&#xff0c;在战略和民用领域有着广泛的应用。陶瓷粉末合成、成型和烧结技术的进步使得先进透明陶瓷材料的微观结构、机械性能和光学性能关系的定制成为可能。透明陶瓷材料大致分为可见光、中波…