跳至主要內容

Json简介及使用

张威大约 6 分钟network数据序列化

Json简介及使用

一、Json简介

是一种轻量级的),采用完全独立于编程语言的来存储和表示数据。 简洁和清晰的层次结构使得 Json 成为理想的数据交换语言,易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率

例如:聊天软件的业务,消息种类分为很多种,例如:登录消息、注册消息、聊天消息、加好友消息等等,。而网络中TCP传输数据时为字节流,因此我们需要数据序列化将其转为字节流发送到对端主机,对端主机读取字节流上报应用服务,再将数据反序列化出来解析使用

image-20240413100255722
image-20240413100255722

优秀的Json开源库JSON for Modern C++:由德国大牛 nlohmann 编写的在 C++ 下使用的 Json 库,具有以下优点:

  1. 直观的语法

  2. 整个代码由一个头文件组成 json.hpp,没有子项目、依赖关系、复杂的构建系统,使用起来非常方便

  3. 使用 C++ 11 标准编写,使用 Json 像使用 STL 容器一样

  4. STL 和 Json 容器之间可以相互转换

  5. 所有类都经过严格的单元测试,覆盖了 100% 的代码,包括所有特殊的行为。此外,还检查了 Valgrind 是否有内存泄漏。为了保持高质量,该项目遵循核心基础设施倡议(CII)的最佳实践。

二、Json语法

2.1 Json语法

:它是,主要有以下特点:

  1. 名称/值对的

  2. 数据由逗号 ,

  3. 使用反斜杆 \字符;

  4. 大括号 {} 保存

  5. 中括号 [] 保存,数组可以包含多个对象;

2.2 Json的两种结构:

  1. 对象:

    大括号 {} 保存的对象是一个无序的名称/值对集合。一个对象以左括号 { 开始, 右括号 } 结束。每个"键"后跟一个冒号 :,名称/值对使用逗号 , 分隔。

  2. 数组:

    中括号 [] 保存的数组是值(value)的有序集合一个数组以左中括号[开始, 右中括号 ]结束,值之间使用逗号 , 分隔。可以是括起来的或者也可以是他们的

2.3 书写格式

key : value格式,类似于我们C++中的map容器,十分简洁清晰,例如:

json js;
js["name"] = "xiaoming";

三、数据序列化实例

Json序列化: 在网络中,常用的数据传输序列化格式有XML、Json、ProtoBuf,在公司级别的项目中,大量的在使用ProtoBuf作为数据序列化的方式,它数据压缩编码传输,占用带宽小,同样的数据信息,是Json的1/10,XML的1/20,但是使用起来比Json稍复杂一些,学习成本较高,所以项目中我们选择常用的Json格式来打包传输数据。

#include "json.hpp"
using json = nlohmann::json;

3.1 普通数据序列化

//1、Json普通数据序列化
void test1() {
    json js;	//添加Json对象
    js["msg_type"] = 2;
    js["from"] = "zhangsan";
    js["to"] = "lisi";
    js["msg"] = "hello, good morning!";
    
    cout << js << endl;
}

序列化输出Json字符串:

利用dump()方法,将dict类型的数据转成str。

void test1() {
    json js;
    js["msg_type"] = 2;
    js["from"] = "zhangsan";
    js["to"] = "lisi";
    js["msg"] = "hello, good morning!";
    
    string sendBuf = js.dump();//Json数据对象 =》 Json字符串
    cout << sendBuf.c_str() << endl;
}

输出**,可以在网络中进行**:

在这里插入图片描述
在这里插入图片描述

3.2 Json添加数组类型

//2、Json添加数组类型
void test2() {
	json js;
	js["id"] = {1, 2, 3, 4, 5}	//添加数组
    js["name"] = "zhangsan";	//添加key-value
    
    js["msg"]["zhangsan"] = "good noon!";
    js["msg"]["lisi"] = "good night!";
    //添加Json对象,上面两句等同于此句一次性添加数组对象
    js["msg"] = {{"zhangsan", "good noon!"}, {"lisi", "good night!"}};
    
    cout << js << endl;    
}
在这里插入图片描述
在这里插入图片描述

数组尽量使用vector可以动态地调整大小

3.3 容器序列化:

//3、容器序列化
void test3() {
    json js;
    
    //直接序列化一个vector容器
    vector<int> vec;
    vec.push_pack(1);
    vec.push_pack(2);
    vec.push_pack(3);
    js["list"] = vec;
    
    //直接序列化一个map容器
    map<int, string> m;
    m.insert({1, "黄山"});
    m.insert({2, "华山"});
    m.insert({3, "泰山"});
    js["local"] = m;
    
    cout << js << endl;
}

四、json::parse()数据反序列化实例

parse : 解析

Json反序列化: 当我们从网络接收到字符串为Json格式时,可以用JSON for Modern C++ 直接反序列化取得数据或者直接反序列化出对象,甚至是容器

4.1 普通数据反序列化

string test4() {
	json js;
    js["msg_type"] = 2;
    js["form"] = "zhangsan";
    js["to"] = "lisi";
    js["msg"] = "good morning!";
    
    string sendBuf = js.dump()
    return sendBuf;    
}

int main() {
    string recvBuf = test4();
    //反序列化,Json字符串 => 数据对象
    json jsBuf = json::parse(recvBuf);
    
    cout << jsbuf["msg_type"] << endl;
    cout << jsbuf["from"] << endl;
    cout << jsbuf["to"] << endl;
    cout << jsbuf["msg"] << endl;
    
    return 0;
}

反序列化输出结果如下,还保留了相应数据类型

4.2 数组类型数据反序列化:

string test5() {
    json js;
    js["id"] = { 1,2,3,4,5 };
    js["name"] = "zhangsan";
    js["msg"] = {{"zhangsan", "good noon!"}, {"lisi", "good night!"}};
    return js.dump();
}

int main() {
    string recvBuf = test5();
    json jsBuf = json::parse(recvBuf);
    cout << jsBuf["id"] << endl;
    
    auto jsMsg = jsBuf["msg"];
    cout << jsMsg["zhangsan"] << endl;
    cout << jsMsg["lisi"] << endl;
    
    return 0;
}

容器反序列化

string test6() {
	vector<int> vec = {1, 2, 3};
    json js;
    js["list"] = vec;
    
    map<int, string> m = {{1, "黄山"},
                         {2, "华山"},
                         {3, "泰山"}};
    js["local"] = m;
    return js.dump();
}

int main() {
    string recvBuf = test6();
    json jsBuf = json::parse(recvBuf);
    
    //将js对象中数组类型直接放入vector容器中
    vector<int> vec = jsBuf["list"];
    for(int v : vec) {
        cout << v << " ";
    }
    cout << endl;
    
    //将js对象中数组类型直接放入map容器中
    map<int, string> mp = jsBuf["local"];
    for(auto it : mp) {
        cout << it.first << " " << it.second << endl;
    }
    cout << endl;
    
    return 0;
}