一、Json简介

Json(JavaScript Object Notation):是一种轻量级的数据交换格式(也叫数据序列化方式),采用完全独立于编程语言的文本格式来存储和表示数据。 简洁和清晰的层次结构使得 Json 成为理想的数据交换语言,易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。 例如:聊天软件的业务,消息种类分为很多种,例如:登录消息、注册消息、聊天消息、加好友消息等等,需要进行具体消息种类的区分,还需要知道消息从谁来,要到哪去,以及消息内容是什么等字段。而网络中TCP传输数据时为字节流,因此我们需要数据序列化将其转为字节流发送到对端主机,对端主机读取字节流上报应用服务,再将数据反序列化出来解析使用。
在这里插入图片描述

优秀的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语法

Json语法:它是JavaScript 对象表示语法的子集,主要有以下特点:
1、数据在名称/值对中;
2、数据由逗号 , 分隔;
3、使用斜杆 \ 来转义字符;
4、大括号 {} 保存对象;
5、中括号 [] 保存数组,数组可以包含多个对象;

Json的两种结构:
1、对象: 大括号 {} 保存的对象是一个无序的名称/值对集合。一个对象以左括号 { 开始, 右括号 } 结束。每个"键"后跟一个冒号 :,名称/值对使用逗号 , 分隔。
2、数组: 中括号 [] 保存的数组是值(value)的有序集合。一个数组以左中括号[开始, 右中括号 ]结束,值之间使用逗号 , 分隔。值(value)可以是双引号括起来的字符串、数值、true、false、 null、对象或者数组,也可以是他们的嵌套类型。

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

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

 

三、数据序列化实例

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

使用前准备:需要提前下载好Json.hpp,使用时引入头文件即可。

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

 

3.1 普通数据序列化

1、Json进行普通数据序列化:

//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字符串:
在这里插入图片描述
 
2、Json序列化:利用dump()方法,将dict类型的数据转成str。

//1、Json普通数据序列化
void test1()
{
    json js; //添加Json对象
    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;
}

输出string字符串,可以在网络中进行传输:
在这里插入图片描述
 
3、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!";

    js["msg"] = {{"zhangsan", "good noon!"}, {"lisi", "good night!"}}; //添加Json对象,上面两句等同于此句一次性添加数组对象
    cout << js << endl;
}

序列化结果如下,输出结果一致的:
在这里插入图片描述
 

3.2 容器序列化

1、容器序列化:

//3、容器序列化
void test3()
{
    json js;

    //3.1 直接序列化一个vector容器
    vector<int> vec;
    vec.push_back(1);
    vec.push_back(2);
    vec.push_back(3);
    js["list"] = vec;

    //3.2 直接序列化一个map容器
    map<int, string> m;
    m.insert({1, "黄山"});
    m.insert({2, "华山"});
    m.insert({3, "泰山"});
    js["local"] = m;

    cout << js << endl;
}

序列化结果如下:
在这里插入图片描述
 

四、数据反序列化实例

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

4.1 普通数据反序列化

1、Json普通数据反序列化:利用parse()方法,从Json字符串反序列化为Json数据对象,类似于容器方便访问。

//4、Json普通数据反序列化
string test4()
{
    json js; //添加Json对象
    js["msg_type"] = 2;
    js["from"] = "zhangsan";
    js["to"] = "lisi";
    js["msg"] = "hello, good morning!";

    string sendBuf = js.dump(); //Json数据对象 =》 Json字符串
    return sendBuf;
}

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

    return 0;
}

反序列化输出结果如下,还保留了相应数据类型。
在这里插入图片描述

2、其它类型数据反序列化:

//5、Json其它类型数据反序列化
string test5()
{
    json js;
    js["id"] = {1, 2, 3, 4, 5}; //添加数组
    js["name"] = "zhangsan"; //添加key-value 

    js["msg"]["zhangsan"] = "good noon!";
    js["msg"]["lisi"] = "good night!";

    js["msg"] = {{"zhangsan", "good noon!"}, {"lisi", "good night!"}}; //添加Json对象,上面两句等同于此句一次性添加数组对象
    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;
}

反序列化结果如下:
在这里插入图片描述
 

4.2 容器反序列化

1、容器反序列化:

//6、容器反序列化
string test6()
{
    json js;

    //6.1 直接序列化一个vector容器
    vector<int> vec;
    vec.push_back(1);
    vec.push_back(2);
    vec.push_back(3);
    js["list"] = vec;

    //6.2 直接序列化一个map容器
    map<int, string> m;
    m.insert({1, "黄山"});
    m.insert({2, "华山"});
    m.insert({3, "泰山"});
    js["local"] = m;

    string sendbuf = js.dump();
    return sendbuf;
}

int main()
{
    string recvBuf = test6();
    json jsbuf = json::parse(recvBuf);

    vector<int> vec = jsbuf["list"]; //将js对象中数组类型直接放入vector容器中
    for (int v : vec)
    {
        cout << v << " ";
    }
    cout << endl;

    map<int, string> mp = jsbuf["local"]; //将js对象中数组类型直接放入map容器中
    for (auto it : mp)
    {
        cout << it.first << " " << it.second << endl;
    }
    cout << endl;

    return 0;
}

反序列化结果如下:
在这里插入图片描述
以上就是我们基于用JSON for Modern C++库的一个简单使用了,如有错误还望批评指正。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐