一、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++库的一个简单使用了,如有错误还望批评指正。