一文教你入门什么是Json?以及C++实现的Json的序列化和反序列化demo

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序列化与反序列

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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值