Json的序列化和反序列化
Json(JavaScript Object Notation)
1、定义
客户端向服务器端发送请求后,服务器端怎么才能把用户需要的数据返回给客户端呢。这时我们就需要用一个指定的格式将数据,按照指定格式返回客户端。这时就有了数据传输的方式Json
。
- 一种轻量级的数据交换格式.易于阅读和理解,也易于机器解析和生成.
2、特征
- JSON 是轻量级的文本数据交换格式,占带宽小(格式是压缩的)
- JSON 具有自我描述性,更易理解
- JSON 采用完全独立于语言的文本格式:JSON 使用 JavaScript 语法来描述数据对象,但是 JSON仍然独立于语言和平台。JSON 解析器和 JSON 库支持许多不同的编程语言。如javascript,python,C,C++等主流语言都支持
和XML简单实例对比:
JSON版本:
{“name”:“fxhl”,"city":"深圳","age":23}
XML版本:
<emp>
<name>fxhl</name>
<city>深圳</city>
<age>23</age>
</emp>
-
1、在可读性方面,JSON和XML的数据可读性基本相同。
-
2、在可扩展性方面,XML天生有很好的扩展性,JSON当然也有,没有什么是XML能扩展,JSON不能的。
-
3、 在解码难度方面,XML的解析得考虑子节点父节点,让人头昏眼花,而JSON的解析难度几乎为0。
-
4、JSON相对于XML来讲,数据的体积小。 没有结束标签,不使用保留字。
-
5、 JSON的速度要远远快于XML。
3、JSON格式 :键值对形式和数组形式
3.1、键值对形式(对象形式)
JSON数据规则是:一个无序的“‘名称/值’对”集合。
- 一个对象以 以
“{”(左括号)
开始,“}”(右括号)
结束; - 每个“名称”后跟一个
:冒号
; - “‘名称/值’ 对”之间使用
,逗号
分隔。
这里的最下面的圈圈包围的,逗号
的反馈图环节,类似于一种循环方式,因为,可以包含多个键值对。
举例
{“person”: {“name”: “pig”,“age”: “18”,“sex”: “man”,“hometown”:
{“province”: “江西省”,“city”: “抚州市”,“county”: “崇仁县” } }}
3.2、数组
数组是值(value)的有序集合。
- 一个数组以
“[”(左中括号)
开始,“]”(右中括号)
结束。 - 值之间间使用
,(逗号)
分隔。
举例:
[“pig”, 18, “man”, “江西省抚州市崇仁县”]
4、6种数据类型(value的类型 )
值(value)可以是双引号括起来的字符串(string)、数值(number)、true、false、 null、对象(object)或者数组(array)。这些结构可以嵌套。
-
1、string:字符串,
必须要用双引号引起来。
-
2、number:数值,与JavaScript的number一致,整数(不使用小数点或指数计数法)最多为 15 位,小数的最大位数是17。
-
3、object:JavaScript的对象形式,{ key:value }表示方式,可嵌套。
-
4、array:数组,JavaScript的Array表示方式[ value ],可嵌套。
-
5、true/false:布尔类型,JavaScript的boolean类型。
-
6、null:空值,JavaScript的null。
实例:
{
"name": "BeJson",
"url": "http://www.bejson.com",
"page": 88,
"isNonProfit": true,
"address": {
"street": "科技园路.",
"city": "江苏苏州",
"country": "中国"
},
"links": [
{
"name": "Google",
"url": "http://www.google.com"
},
{
"name": "Baidu",
"url": "http://www.baidu.com"
},
{
"name": "SoSo",
"url": "http://www.SoSo.com"
}
]
}
5、序列化和反序列化
5.1、定义
当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象。
- 把Java对象转换为字节序列的过程称为对象的序列化。
- 把字节序列恢复为Java对象的过程称为对象的反序列化。
对象的序列化主要有两种用途:
- 1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;
- 2) 在网络上传送对象的字节序列。
Javascript实例:
参考
JSON.stringify() - 将对象序列化为JSON字符串
JSON.parse() - 将JSON数据解析为Javascript对象
结果输出:
更好的Java实例
5.2、C++简单实现JSON序列化与反序列
#pragma once
#include <string>
#include <vector>
#include "json/json.h"
using std::string;
using std::vector;
struct CJsonObejectBase
{
protected:
enum CEnumJsonTypeMap//枚举支持的多种数据类型
{
asInt = 1,
asUInt,
asString,
asInt64,
asUInt64,
};
public:
CJsonObejectBase(void){}//构造函数
public:
virtual ~CJsonObejectBase(void){}//析构
string Serialize()//序列化
{
Json::Value new_item;
int nSize = m_listName.size();//元素个数
for (int i=0; i < nSize; ++i )
{
void* pAddr = m_listPropertyAddr[i];//pAddr 指向序列化数组元素
switch(m_listType[i])//基于不同的数据类型,对元素进行类型转换
{
case asInt:
new_item[m_listName[i]] = (*(INT*)pAddr);
break;
case asUInt:
new_item[m_listName[i]] = (*(UINT*)pAddr);
break;
case asInt64:
new_item[m_listName[i]] = (*(LONGLONG*)pAddr);
break;
case asUInt64:
new_item[m_listName[i]] = (*(ULONGLONG*)pAddr);
break;
case asString:
new_item[m_listName[i]] = (*(string*)pAddr);
default:
//我暂时只支持这几种类型,需要的可以自行添加
break;
}
}
Json::FastWriter writer;
std::string out2 = writer.write(new_item); //执行序列化数据的写入操作
return out2;//返回序列化数据
}
bool DeSerialize(const char* str)//反序列化
{
Json::Reader reader; //读对象
Json::Value root;
if (reader.parse(str, root))//反序列化函数
{
int nSize = m_listName.size();
for (int i=0; i < nSize; ++i )
{
void* pAddr = m_listPropertyAddr[i];
switch(m_listType[i])//基于不同的元素数据类型定义,得到序列化中的元素get()操作
{
case asInt:
(*(INT*)pAddr) = root.get(m_listName[i], 0).asInt();
break;
case asUInt:
(*(UINT*)pAddr) = root.get(m_listName[i], 0).asUInt();
break;
case asInt64:
(*(LONGLONG*)pAddr) = root.get(m_listName[i], 0).asInt64();
break;
case asUInt64:
(*(ULONGLONG*)pAddr) = root.get(m_listName[i], 0).asUInt64();
break;
case asString:
(*(string*)pAddr) = root.get(m_listName[i], "").asString();
default:
//我暂时只支持这几种类型,需要的可以自行添加
break;
}
}
return true;
}
return false;
}
protected:
//存储序列化数据的操作
void SetProperty(string name, CEnumJsonTypeMap type, void* addr)
{
m_listName.push_back(name);//插入元素
m_listPropertyAddr.push_back(addr);//插入地址
m_listType.push_back(type);//插入数据类型
}
virtual void SetPropertys() = 0;
vector<string> m_listName;//用于存放需要序列化的数据元素
vector<void*> m_listPropertyAddr;//用于存放需要序列化的数据元素地址
vector<CEnumJsonTypeMap> m_listType;
};
此类主要有三个函数:Serialize、DeSerialize及 SetPropertys、SetProperty
,其中前两个函数主要是用来实现对象的序列化与反序列化;SetPropertys
是一个纯虚函数,如果一个类需要具备序列化功能,只需要从此类继承,同时调用SetProperty
函数,将各个字段的属性进行设置即可。
使用对象的序列化及反序列化功能
要使对象具体相应功能,需要继承上述的基类,如下:
struct CTestStruct : public CJsonObejectBase
{
CTestStruct()
{
SetPropertys();
}
ULONGLONG MsgID;//定义个人化的数据元素,这里是ID
string MsgTitle;//这是标题
string MsgContent;//这是内容
protected:
//子类需要实现此函数,并且将相应的映射关系进行设置
virtual void SetPropertys()
{
SetProperty("MsgID", asUInt64, &MsgID);
SetProperty("MsgTitle", asString, &MsgTitle);
SetProperty("MsgContent", asString, &MsgContent);
}
};
序列化:
void CJasonSerializeDlg::OnBnClickedOk()
{
CTestStruct stru;
stru.MsgID = 11223344;
stru.MsgTitle = "黑黑";
stru.MsgContent = "哈哈";
CString strTest = stru.Serialize().c_str();//序列化
AfxMessageBox(strTest);//输出序列化数据
}
反序列化:
void CJasonSerializeDlg::OnBnClickedOk2()
{
const char* pstr = "{\"MsgContent\":\"哈哈22\",\"MsgID\":11111111111111111,\"MsgTitle\":\"黑黑22\"}";
CTestStruct stru;
stru.DeSerialize(pstr);//反序列化
CString strShow = "";
strShow.Format("MsgID:%I64u\r\nMsgTile:%s\r\nMsgContent:%s", stru.MsgID, stru.MsgTitle.c_str(), stru.MsgContent.c_str());
AfxMessageBox(strShow);
}
参考
1、https://blog.csdn.net/pupilxiaoming/article/details/80988013
2、https://www.cnblogs.com/abella/p/11125685.html
3、https://blog.csdn.net/tragicguy/article/details/9150569