Json介绍——序列化与反序列化

概述:

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

数据序列化格式还有:xml、protobuf,其中protobuf存储数据更为高效,在企业级项目中更常见。——RPC项目用的就是protobuf

本项目中用的Json第三方库是Json for Modern C++,由德国大牛nlohmann编写的在C++下使用的Json库。该库只有一个json.hpp头文件,使用C++11编写,使得使用json就像使用STL容器一样,且STL容器和json之间可以相互转换

序列化是将数据结构或是对象转换为二进制串(字节序列)的过程,也就是将具有一定结构的对象转换为可以存储或传输的形式。在序列化期间,对象将其当前状态写入到临时或持久性存储区(如硬盘)。这样我们就可以通过从存储区中读取或反序列化对象的状态,重新创建该对象

反序列化就是上述的逆过程。

比如我们把json格式的对象转换成字符串,再转换成char*,这样就能在网络上传输,或者写进硬盘——由结构化的数据转成地址值

反过来我们把从网络上接收到的字符串对象转成json对象,就是重新构建出json对象结构,这就是反序列化

所以对象序列化的目的:

1、把对象的字节序列永久保存在硬盘上(以某种储存方式使自定义对象持久化);

2、在网络上传送对象的二进制序列(将对象从一个地方传递到另一个地方);

3、使程序更具维护性。

其实就是两个函数:

序列化--------js.dump()//不用传参,json对象js访问成员函数

反序列化-----json::parse(字符串对象)

下列测试代码来自施磊老师课程笔记

一. 序列化

测试1:

#include "json.hpp"
using json = nlohmann::json;
#include
using namespace std;
//json序列化演示
void func1(){
    json js;
    //就像map容器一样,key - value
    js["msg_num"] = 2;
    js["from"] = "zhang san";
    js["to"] = "li si";
    js["mas"] = "hello, it's my first cpp program";
    cout<< js <<endl;
}
int main(){
    func1();
    return 0;
}

神奇,可以直接输出json对象js————json肯定对输出运算符做了重载,存数据的时候又能像map容器一样。

输出结果:

{"from":"zhang san","mas":"hello, it's my first cpp program","msg_type":2,"to":"li si"}

可以看到,并不是msg_type第一个插进去就第一个输出/第一个位置存,它是按照key的首字母顺序来存放和输出的,就像有序哈希表map一样

json 转化为 字符串

json要通过网络发送肯定还是要转成字符串类型,而string在网络上传播是char*形式

string Str = json.dump();//dump函数就可以将json的序列化数据转成string形式,dump本意有转储,导出的意思
//string也封装了将string转换为char*的方法
char* a = Str.c_str();
cout<< a <<endl;

变成字符串其实输出的还是之前那样的结果,相当于在外面加了“”符号

测试2:

json的键对应的值value除了上面的int ,string类型,还可以是数组类型,甚至是json类型,而且键本身也可以是二维数组类型,如下:

void func2(){
    json js;
    js["id"] = {1, 2, 3, 4, 5};
    js["name"] = "zhang san";
    //添加对象,key可以是二维数组
    js["msg"]["liu shuo"] = "hello A";
    js["msg"]["zhang san"] = "hello B";//js[键1][键2]
    //下面等同于上面两行,两种形式输出都一样
    js["msg"] = {{"liu shuo", "hello A"}, {"zhang san", "hello B"}};//用两个json对象给js的msg赋值
    cout<<js<<endl;
}

输出:

{"id":[1,2,3,4,5],"msg":{"liu shuo":"hello A","zhang san":"hello B"},"name":"zhang san"}

可以看到msg对应的值是一个json,两个json赋值给msg后变成了一个json,而且,js["msg"]["liu shuo"]的意义就是先访问js的键msg,再访问msg中的键liu shuo,还有就是,liu和zhang的顺序也被改了,因为两者在msg这个json里面就是键,是有顺序的

测试3:

json甚至能将容器序列化,其实就是value还可以是容器类型

void func3(){
    json js;
    //序列化vector容器
    vector<int> vec;
    vec.push_back(1);
    vec.push_back(2);
    vec.push_back(5);
    js["list"] = vec;

    //序列化map容器
    map<int, string> m;
    m.insert({1, "黄山"});
    m.insert({2, "华山"});
    m.insert({3, "泰山"});
    js["path"] = m;
    cout<<js<<endl;
}

输出:

{"list":[1,2,5],"path":[[1,"黄山"],[2,"华山"],[3,"泰山"]]}

map这个键值对容器转成json后,变成二维数组了

二. 反序列化

假设我们收到字符串形式的json,我们把它转成json格式,用json::parse()函数,parse是语法分析,解析。

其实就是,对方服务器有json数据,转成字符串,这样方便发给我们,我们再把它重塑为json

下面测试123是对应上面测试123的反序列化

测试1:

string func1(){
    json js;
    //就像map容器一样,key - value
    js["msg_type"] = 2;
    js["from"] = "zhang san";
    js["to"] = "li si";
    js["msg"] = "hello, it's my first cpp program";
    string Str = js.dump();
    return Str;
}
int main(){
    string s = func1();
    json js = json::parse(s);
    cout<<js["msg_type"]<<endl;
    cout<<js["from"]<<endl;
    cout<<js["msg"]<<endl;
    return 0;
}

输出:

2
"zhang san"
"hello, it's my first cpp program"

测试2:

string func2(){
    json js;
    js["id"] = {1, 2, 3, 4, 5};
    js["name"] = "zhang san";
    js["msg"]["liu shuo"] = "hello A";
    js["msg"]["zhang san"] = "hello B";
    return js.dump();
}
int main(){
    json js = json::parse(func2());
    cout<<js["id"]<<endl;
    cout<<js["msg"]<<endl;
    cout<<js["msg"]["zhang san"]<<endl;
    return 0;
}

输出:

[1,2,3,4,5]
{"liu shuo":"hello A","zhang san":"hello B"}
"hello B"

下面测试3更能体现反序列化的意义!

测试3:

string func3(){
    json js;
    //序列化vector容器
    vector<int> vec;
    vec.push_back(1);
    vec.push_back(2);
    vec.push_back(5);
    js["list"] = vec;

    //序列化map容器
    map<int, string> m;
    m.insert({1, "黄山"});
    m.insert({2, "华山"});
    m.insert({3, "泰山"});
    js["path"] = m;
    return js.dump();
}
int main(){
    json js = json::parse(func3());
    vector<int> nums = js["list"];//因为js里面的list的值是vector形式数据
    map<int, string>mp = js["path"];
    for(auto& a : nums){
        cout<<a<<endl;
    }
    for(int i = 0; i < mp.size(); ++i){
        cout<<mp[i]<<endl;
    }
    return 0;
}

结果:

1
2
5
   //这里输出了一个空字符串,map[0]对应的value(string类型)
黄山
华山
泰山

上述代码中,用下标去给map做输出,而map的[]里应该是key,所以i = 0时,因为map没有对应元素,所以被新增到容器中,此时容器大小变为4,所以能访问下标[3],map[0]其对应的初始值为空字符串

所以用迭代器访问map更好,这样不会新增元素,而且不会越界。

for(auto& p : mp){
	cout<<p.first<<" "<<p.second<<endl;
}

加上上述代码后输出如下:
Json介绍——序列化与反序列化_第1张图片

你可能感兴趣的:(项目笔记,json,c++)