C++数据序列化之MessagePack

msgpack官方地址:http://msgpack.org/

msgpack GITHUB地址:https://github.com/msgpack


对于msgPack,官方是这样解释的:

MessagePack  是一个高效的二进制序列化格式。它让你像JSON一样可以在各种语言之间交换数据。但是它比JSON更快、更小。小的整数会被编码成一个字节,短的字符串仅仅只需要比它的长度多一字节的大小。


It’s like JSON.  but fast and small.

这里,说了,msgPack有两个优势,更快(fast),更小(small).

想要了解这些优势原因,我们当然得先知道msgPack在内存中是怎么存储的,


json数据应该已经算是很小了,没有什么冗余的数据了,但msgpack是从哪些方面让存储占用内存更小的呢?

举例:

json

{“name“:”heyue“,”sex“:”\u7537“,”company“:”sina“,”age“:30

这个json长度为57字节,但是为了表示这个数据结构(所有标红色的地方就是他为了表示这个数据结构而不得不添加的),它用了23个字节(就是那些大括号、引号、冒号之类的,他们是白白多出来的)。大家可以去http://json.org/ 上看看json的数据标示定义。

换成MessagePack,我只能给大家贴代码和结果了,38字节.

msg压缩规则是什么呢?

1.true、false 之类的:这些太简单了,直接给1个字节,(0xc2 表示true,0xc3表示false

2.不用表示长度的:就是数字之类的,他们天然是定长的,是用一个字节表示后面的内容是什么东东,比如用(0xcc 表示这后面,是个uint 8,用oxcd表示后面是个uint 16,用 0xca 表示后面的是个float 32).

3.不定长的:比如字符串、数组,类型后面加 1~4个字节,用来存字符串的长度,如果是字符串长度是256以内的,只需要1个字节,MessagePack能存的最长的字符串,是(2^32 -1 ) 最长的4G的字符串大小。

4.ext结构:表示特定的小单元数据。

5.高级结构:MAP结构,就是key=>val 结构的数据,和数组差不多,加1~4个字节表示后面有多少个项。

这个是官方的数据表示结构文档:https://gist.github.com/frsyuki/5432559

总的来说,MessagePack对数字、多字节字符、数组等都做了很多优化,减少了无用的字符,二进制格式,也保证不用字符化带来额外的存储空间的增加,所以MessagePack比JSON小是肯定的,小多少,得看你的数据。如果你用来存英文字符串,那几乎是没有区别….



那么,快又是从哪个方面快起来的呢?

先说说JSON怎么解析吧,我们开发中一般都用cJSON这个库,cJSON存储的时候是采用链表存储的,其访问方式很像一颗树。每一个节点可以有兄妹节点,通过next/prev指针来查找,它类似双向链表;每个节点也可以有孩子节点,通过child指针来访问,进入下一层。问题就是首先,构造这个链表的时候,得一个字符一个字符地匹配过去吧,得判断是不是引号、括号之类的吧…

但是MessagePack 则简单多了,直接一遍遍历过去了,从前面的数据头,就可以知道后面的是什么数据,指针应该向后移动多少,比JSON的构建链表少了很多比较的过程。


应用1:

	using namespace msgpack;
	using namespace std;
	     msgpack::sbuffer  sbuf;
	     msgpack::packer<msgpack::sbuffer>   pker(&sbuf);
	
	     // 序列化
	     pker.pack_map(3);
	     pker.pack(string("type"));
	     pker.pack(3);
	     pker.pack(string("ratio"));
	     pker.pack(2.15);
	     pker.pack(string("msg"));
	     pker.pack(string("hello world"));
	
		 int compressSize = sbuf.size();
	     // 反序列化
	     msgpack::v1::unpacked  unpack;
	     msgpack::v1::unpack(&unpack, sbuf.data(), sbuf.size());
	
	     // 直接输出结果
	     msgpack::object  obj = unpack.get();
	     cout << obj << endl;
	
	     // 访问具体键值对
	     msgpack::v2::object_kv*  pkv;
	     msgpack::v2::object_kv*  pkv_end;
	     msgpack::v2::object      pk, pv;
	     if (obj.via.map.size > 0)
		     {
			 pkv = obj.via.map.ptr;
		        pkv_end = obj.via.map.ptr + obj.via.map.size;
				do
		         {
		             pk = pkv->key;

					 std::string _vecRString;
					 pk.convert(_vecRString);

					 pv = pkv->val;
		
		             ++pkv;
		         }
		         while (pkv < pkv_end);
		     }

应用2:(类的序列化)

类的序列化非常简单,只需要类中添加一行宏,就可以实现数据的序列化

#include <string>
#include <vector>
#include <msgpack.hpp>
#include <iostream>
class CommandMsg {
public:
	std::string m_mapName;
	std::vector<int> m_iVec;
	std::vector<std::string> m_sVec;

	std::map<std::string, int> m_map;

public:
	MSGPACK_DEFINE(m_mapName, m_iVec, m_sVec, m_map);
};

	std::vector<CommandMsg> my_class_vec;
	CommandMsg tempMsg;
	tempMsg.m_mapName = "hello,dog";
	tempMsg.m_map.insert(std::make_pair("aa1", 10));
	tempMsg.m_map.insert(std::make_pair("aa2", 20));
	my_class_vec.push_back(tempMsg);


	CommandMsg tempMsg2;
	tempMsg2.m_mapName = "openGL";
	tempMsg2.m_map.insert(std::make_pair("001", 1));
	tempMsg2.m_map.insert(std::make_pair("002", 2));
	tempMsg2.m_map.insert(std::make_pair("003", 3));
	my_class_vec.push_back(tempMsg2);


	// add some data
	msgpack::v2::sbuffer buffer;
	msgpack::v2::pack(buffer, my_class_vec);

	msgpack::v1::unpacked msg;
	msgpack::v1::unpack(&msg, buffer.data(), buffer.size());

	msgpack::v1::object obj = msg.get();
	std::vector<CommandMsg> my_class_vec_r;
	obj.convert(&my_class_vec_r);

	for (int i = 0; i < my_class_vec.size(); i++) 
	{
		std::string str_Name = my_class_vec[i].m_mapName;

		std::map<std::string, int>::iterator iter = my_class_vec[i].m_map.begin();
		while (iter!= my_class_vec[i].m_map.end())
		{
			std::string str_key=iter->first;
			int value = iter->second;
			iter++;
		}
	}


  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值