Json-Rpc框架(JsonCpp库使用介绍)

阅读导航

  • 引言
  • 一、Json数据格式
  • 二、JsonCpp介绍
  • 三、JsonCpp使用示例
  • 四、封装Json工具类

引言

JsonCpp,作为一个广受欢迎的C++ JSON库,以其易用性、高性能和丰富的功能集赢得了众多开发者的青睐。它不仅提供了简洁直观的API用于JSON数据的解析和生成,还通过良好的异常处理机制和类型安全的设计,确保了代码的稳定性和可维护性。在接下来的内容中,我们将详细介绍JsonCpp的基本用法、核心特性以及它是如何与我们的Json-Rpc框架无缝集成的,从而帮助我们更加高效地处理JSON数据,推动项目向前发展。

一、Json数据格式

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它以易于人阅读和编写的文本格式来存储和表示结构化数据,且这种格式独立于任何编程语言。

🎯例如:我们想表示⼀个同学的学⽣信息

  • 💻C++代码表示
char *name = "xx";
int age = 18;
float score[3] = {88.5, 99, 58};
  • 💻Json 表⽰
{"姓名" : "xx","年龄" : 18,"成绩" : [88.5, 99, 58],"爱好" : {"书籍" : "西游记","运动" : "打篮球"}
}

JSON是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。它基于JavaScript的一个子集,但JSON是独立于语言的,并且被许多现代编程语言所支持。JSON的主要数据类型包括:

  1. 对象:对象在JSON中以花括号{}包围,它们由键值对组成,键和值之间通过冒号:分隔,每对键值对之间使用逗号,分隔。键必须是字符串,而值可以是字符串、数字、布尔值、数组、对象或null。

  2. 数组:数组在JSON中以中括号[]包围,它们包含了一系列的值,这些值可以是字符串、数字、布尔值、数组、对象或null。数组中的值通过逗号,分隔。

  3. 字符串:字符串在JSON中必须使用双引号""包围,不能使用单引号。字符串中可以包含转义字符,例如\n表示换行,\"表示双引号本身等。

  4. 数字:JSON中的数字可以是整数或浮点数,不需要额外的引号或格式标记。数字可以非常大或非常精确,且遵循IEEE 754标准。

  5. 布尔值:布尔值在JSON中表示为truefalse,它们不区分大小写,但习惯上写作小写形式。

二、JsonCpp介绍

Jsoncpp 库是一个专注于处理JSON格式数据的C++库,它提供了两个核心功能:序列化和反序列化

序列化功能允许开发者将C++中的数据结构(如对象、数组等)转换成JSON格式的字符串,这种字符串形式便于数据的存储、传输或网络交换。

反序列化功能则是这一过程的逆操作,它能够将JSON格式的字符串解析回C++中的数据结构,使得程序能够方便地读取和处理这些数据。

Json 数据对象类的表⽰

class Json::Value {  
public:  // 赋值操作符重载  Value& operator=(const Value& other);  // 通过字符串键访问成员,支持赋值和获取  Value& operator[](const std::string& key);  Value& operator[](const char* key);  // 移除具有指定键的成员  Value removeMember(const char* key);  // 通过索引访问数组元素(只读)  const Value& operator[](ArrayIndex index) const;  // 向数组末尾添加元素  Value& append(const Value& value);  // 获取数组元素的数量  ArrayIndex size() const;  // 类型转换函数  std::string asString() const;   // 转换为std::string  const char* asCString() const;  // 转换为const char*  int asInt() const;              // 转换为int  float asFloat() const;          // 转换为float  bool asBool() const;            // 转换为bool  
};

📌Jsoncpp 库主要借助三个类以及其对应的少量成员函数完成序列化及反序列化

  • 序列化接口
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;
}
  • 反序列化接口
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;
}

三、JsonCpp使用示例

#include <iostream>  
#include <sstream>  
#include <string>  
#include <memory>  
#include <jsoncpp/json/json.h>  // 实现数据的序列化,将Json::Value对象转换为JSON格式的字符串  
bool serialize(const Json::Value &val, std::string &body) {  std::stringstream ss; // 创建一个字符串流,用于存储序列化后的JSON字符串  // 先实例化一个StreamWriterBuilder对象,它是用于创建StreamWriter对象的工厂  Json::StreamWriterBuilder swb;  // 通过StreamWriterBuilder对象来生成一个StreamWriter对象的智能指针  std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());  // 调用StreamWriter对象的write方法,将Json::Value对象序列化到字符串流中  int ret = sw->write(val, &ss);  if (ret != 0) { // 如果序列化失败(通常ret应为0表示成功)  std::cout << "json serialize failed!\n";  return false;  }  body = ss.str(); // 将字符串流中的内容赋值给body  return true;  
}  // 实现json字符串的反序列化,将JSON格式的字符串解析为Json::Value对象  
bool unserialize(const std::string &body, Json::Value &val) {  // 实例化CharReaderBuilder对象,它是用于创建CharReader对象的工厂  Json::CharReaderBuilder crb;  // 通过CharReaderBuilder对象生成一个CharReader对象的智能指针  std::string errs; // 用于存储解析过程中可能出现的错误信息  std::unique_ptr<Json::CharReader> cr(crb.newCharReader());  // 调用CharReader对象的parse方法,将JSON字符串解析为Json::Value对象  // 注意:parse方法的第二个参数是字符串的结束位置(指向字符串末尾的下一个位置)  bool ret = cr->parse(body.c_str(), body.c_str() + body.size(), &val, &errs);  if (ret == false) { // 如果解析失败  std::cout << "json unserialize failed : " << errs << std::endl;  return false;  }  return true;  
}  int main()  
{  // 初始化一些示例数据  const char *name = "小明";  int age = 18;   const char *sex = "男";  float score[3] = {88, 77.5, 66};  // 创建一个Json::Value对象来存储学生信息  Json::Value student;  student["姓名"] = name; // 添加姓名  student["年龄"] = age;  // 添加年龄  student["性别"] = sex;  // 添加性别  // 添加成绩,需要逐个添加,因为score是一个数组,而Json::Value需要逐个元素处理  for (int i = 0; i < 3; ++i) {  student["成绩"].append(score[i]);  }  // 添加爱好,爱好也是一个Json::Value对象,包含书籍和运动两个字段  Json::Value fav;  fav["书籍"] = "西游记";  fav["运动"] = "打篮球";  student["爱好"] = fav; // 将爱好对象添加到学生信息中  std::string body;  // 序列化学生信息到字符串body中  serialize(student, body);  std::cout << body << std::endl; // 打印序列化后的JSON字符串  // 示例:反序列化一个JSON字符串  std::string str = R"({"姓名":"小黑", "年龄": 19, "成绩":[32, 45, 56]})";  Json::Value stu;  bool ret = unserialize(str, stu);  if (ret == false)   return -1; // 如果反序列化失败,则退出程序  // 访问并打印反序列化后的JSON对象中的信息  std::cout << "姓名: " << stu["姓名"].asString() << std::endl;  std::cout << "年龄: " << stu["年龄"].asInt() << std::endl;  int sz = stu["成绩"].size();  for (int i = 0; i < sz; i++) {  std::cout << "成绩: " << stu["成绩"][i].asFloat() << std::endl;  }  return 0;  
}

编译运⾏程序查看序列化和反序列化结果

{"姓名":"小明","年龄":18,"性别":"男","成绩":[88.0,77.5,66.0],"爱好":{"书籍":"西游记","运动":"打篮球"}
}  姓名: 小黑  
年龄: 19  
成绩: 32  
成绩: 45  
成绩: 56

四、封装Json工具类

#include <iostream>  
#include <sstream>  
#include <string>  
#include <memory>  
#include <jsoncpp/json/json.h>  class json_util  
{  
public:  // 序列化: Json对象 -> 字符串  // 输入输出型参数  // root输入参数:表示要序列化的json对象  // str输出参数: 表示序列化之后的字符串  static bool serialize(const Json::Value &root, std::string &str)  {  Json::StreamWriterBuilder swb;  std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());  std::stringstream ss;  int ret = sw->write(root, &ss);  if (ret != 0) {  std::cout << "Serialize failed!" << std::endl;  return false;  }  str = ss.str();  return true;  }  // 反序列化: 字符串 -> Json对象  // 输入输出型参数  // str输入参数: 表示需要反序列化的字符串  // root输出参数:表示反序列化后的json对象  static bool unserialize(const std::string &str, Json::Value &root)  {  Json::CharReaderBuilder crb;  std::unique_ptr<Json::CharReader> cr(crb.newCharReader());  std::string errs; bool ret = cr->parse(str.c_str(), str.c_str() + str.size(), &root, &errs);  if (!ret) {  std::cout << "UnSerialize failed! Errors: " << (errs.empty() ? "None" : errs) << std::endl;  return false;  }  return true;  }  
};  

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

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

相关文章

职场中的10个“人情世故”,随处可见

职场上&#xff0c;“现实”是主基调。如果不通#人情世故#&#xff0c;可能举步维坚。很多时候&#xff0c;人情世故并不是什么高深的学问&#xff0c;就是在点点滴滴间&#xff0c;只要稍加注意&#xff0c;就能学通。下面这10条&#xff0c;是职场很常见的人情世故。 1、登门…

InnoDB 事务模型

文章目录 InnoDB 事务模型事务ACID特性事务隔离级别 事务操作事务并发问题事务数据读写类型Consistent Nonlocking Reads 快照读Locking Reads 加锁读 MVCC 并发控制实现原理InnoDB 隐藏列Read ViewUndo log实现过程 MVCC与隔离级别MVCC和辅助索引 幻读幻行问题可重复读MVCC会出…

HTB:Synced[WriteUP]

目录 连接至HTB服务器并启动靶机 1.What is the default port for rsync? 2.How many TCP ports are open on the remote host? 3.What is the protocol version used by rsync on the remote machine? 4.What is the most common command name on Linux to interact w…

一些关于上传数据-p7zip-full-压缩包的经验

目录 前言 7z 简介 Windows如何压缩tar.gz格式 一、下载7-ZIP 二、tar文件进一步压缩 说明&#xff1a; 前言 本人每次在linux服务器上执行apt-get install p7zip-full命令&#xff0c;都会有复杂依赖报错&#xff08;因为实验过程中用到的依赖包太多了&#xff09;&…

[Python学习日记-39] 闭包是个什么东西?

[Python学习日记-39] 闭包是个什么东西&#xff1f; 简介 闭包现象 闭包意义与作用 简介 在前面讲函数和作用域的时候应该提到过&#xff0c;当函数运行结束后会由 Python 解释器自带的垃圾回收机制回收函数内作用域已经废弃掉的变量&#xff0c;但是在 Python 当中还有一种…

Linux中的多线程

Linux线程概念 在一个程序里的一个执行路线就叫做线程&#xff08;thread&#xff09;。更准确的定义是&#xff1a;线程是“一个进程内部的控制序 列” 进程是系统分配资源的基本实体 线程是CPU调度的基本单位 POSIX线程库 创建线程 功能&#xff1a;创建一个新的线程 原…

Tkinter打包成EXE安装文件

打包成 .exe可执行文件 1. 安装PyInstaller&#xff0c;命令如下&#xff1a; pip install pyinstaller2. 编写你的Tkinter应用程序&#xff1a; 创建一个Python文件&#xff0c;例如app.py&#xff0c;并写入你的Tkinter代码。 3. 在 app.py 文件所在的目录使用PyInstaller…

从零开始讲PCIe(5)——66MHZ的PCI总线与其限制

一、前言 在之前的内容中&#xff0c;我们已经基本了解了PCI总线的设计思路和传输机制&#xff0c;之前的内容我们都是基于33MHZ版本的PCI总线进行学习的&#xff0c;为了支持更到的带宽&#xff0c;PCI协议还有一种66MHZ的版本。 二、高带宽PCI&#xff08;66MHZ&#xff09;…

UML类图全解析

1.UML的基本介绍 1.1什么是UML 1.UML > 统一建模语言&#xff0c;是一种用于软件系统分析和设计的语言工具&#xff0c;它用于帮助软件开发人员进行思考和记录思路的结果。 2.UML本身是一套符号的规定&#xff0c;就像数学符号和化学符号一样&#xff0c;这样符号用于描述软…

dll动态库加载失败导致程序启动报错以及dll库加载失败的常见原因分析与总结

目录 1、问题说明 2、dll库的隐式加载与动态加载 2.1、dll库的隐式加载 2.2、dll库的显式加载 3、使用Process Explorer查看进程加载的dll库信息以及动态加载的dll库有没有加载成功 3.1、使用Process Explorer查看进程加载的dll库信息 3.2、使用Process Explorer查看动态…

交叠型双重差分法

交叠型双重差分法&#xff08;Staggered Difference-in-Differences, Staggered DiD&#xff09;是一种扩展的双重差分&#xff08;Difference-in-Differences, DiD&#xff09;方法&#xff0c;用于处理多个时间点的政策干预或处理组&#xff08;treatment group&#xff09;并…

JavaWeb的小结02

第2章-第2节 一、知识点 HttpServletRequest请求对象、HttpServletResponse响应对象、响应内容类型Content-Type、请求转发、重定向、ServletContext对象。 二、目标 深刻理解HttpServletRequest对象的作用。 深刻理解HttpServletResponse对象的作用。 掌握HttpServletRequ…

企业必备:搭建大模型应用平台实操教程

最近AI智能体很火&#xff0c;AI智能体平台化产品肯定属于大公司的。但在一些场景下&#xff0c;尤其是对业务数据要求很高的公司&#xff0c;那就只能用私有大模型。不一定完全是为了对外提供服务&#xff0c;对内改造工作流也是需要的。所以 我感觉未来大部分企业都会搞一个…

普渡PUDU MT1:AI赋能,破解大面积场景清洁新挑战

普渡AI智能扫地机器人PUDU MT1:破解大面积场景清洁难题的新利器 在仓储物流、工业车间、交通枢纽、大型商场等大面积场景中,清洁难题一直是管理者们头疼的问题。这些区域面积广阔,清洁任务繁重,传统清洁方式难以胜任。然而,普渡机器人最新推出的AI智能扫地机器人PUDU MT1…

什么是 HTTP Get + Preflight 请求

当在 Chrome 开发者工具的 Network 面板中看到 GET Preflight 的 HTTP 请求方法时&#xff0c;意味着该请求涉及跨域资源共享 (CORS)&#xff0c;并且该请求被预检了。理解这种请求的背景&#xff0c;主要在于 CORS 的工作机制和现代浏览器对安全性的管理。 下面是在 Chrome …

ConcurrentHashMap在JDK1.7和1.8的区别,详解

目录 1.了解HashMap底层插入原理 2.ConcurrentHashMap 是什么&#xff1f; HashTable的实现 3.ConcurrentHashMap 1.7和1.8的区别 4、JDK1.7 中的ConcurrentHashMap实现原理 6、JDK1.8中的ConcurrentHashMap 7.链表转红黑树条件 1.8 put方法 8.并发扩容 9.总结 首先呢…

Origin正态分布检验

在spass中用Shapiro-Wilk检验--正态分布检测 Shapiro-Wilk检验--正态分布检测_spss shapiro-wilk检验-CSDN博客

数据服务-实时同步(sersync)

1. 概述 1.之前我们通过rsync定时任务实现定时备份/同步 2. 对于NFS我们需要进行实时同步 2. Sersync原理 3. 上手指南 环境主机web0110.0.0.7(nfs客户端)nfs0110.0.0.31(rsync客户端) (nfs服务端)backup10.0.0.41(rsync服务端) 3.1 rsync服务端准备 参考: 数据服务-备份服务…

好用便宜的头戴式耳机哪款好?强推四款高分爆单耳机精品!

音质&#xff0c;是耳机的灵魂。头戴式降噪耳机&#xff0c;以其卓越的音质表现&#xff0c;为您演绎音乐的真谛。无论是细腻的情感表达&#xff0c;还是震撼的音效体验&#xff0c;它都能让您感受到音乐的魅力所在。那好用便宜的头戴式耳机哪款好&#xff1f;&#xff0c;这里…

为什么芯片有多个不同的供电电压?

一、为什么芯片有多个不同的供电电压&#xff1f; 优化性能与功耗&#xff1a;芯片的核心部分&#xff08;Core&#xff09;和输入输出部分&#xff08;IO&#xff09;可能采用不同的电压。核心电压通常较低&#xff0c;以减少功耗和发热&#xff0c;提高能效&#xff1b;而IO电…