Protocol-buffers 序列化规则

Protocol-buffers序列化规则

Type Meaning Used For
0 Varint int32, int64, uint32, uint64, sint32, sint64, bool, enum
1 64-bit fixed64, sfixed64, double
2 Length-delimited string, bytes, embeded, messages, packed repteated fields
5 32-bit fixed32, sfixed32, float

一、基本结构

第一个字节中存储序列化的数据编号和序列化方式,字节的后3位的值代表了序列化方式,取值范围为[0, 5],其中3和4为已弃用的序列化类型。字节的前5位代表的序列化的字段编号。比如如下的类型

message Test1
{
	optional int32 a = 1;
}

如果a被赋值为150,那么被序列化后的值为

08 96 01

第一个字节08的二进制值为0000 1000,前5位数值为1,代表设置给a的编号,后三位值为0,代表以Varint的形式序列化,后两个字节的值就是150以Varint方式序列化后的值。

二、序列化规则

1、Varint

这种方式用于序列化整型数据,会根据数值的大小动态改变占用的字节长度,越小的数值占用的更少的字节数。该序列化方式以一个字节为最小单位,以每个字节的第一位的值判断是否到了数据末尾,值为0代表无后续数值,值为1代表还有后续数据。后7位用于存储原数据,存储顺序以整数的低位优先。例如

0000 0001 代表 1
1010 1100 0000 0010 代表300

0000 0001 
	第一位值为0,代表已是数据的最后一个字节,数据值为就为1
	
1010 1100 0000 0010 
	第一个字节为1010 1100的第一位为1,代表下一个字节仍存储数据信息,而这个字节存储的信息为010 1100
	第二个字节为0000 0010的第一位为0,代表该字节为存储的数据的最后一个字节,存储的信息为0000 0010
	按照整数低位优先的顺序,010 1100代表低位,0000 0010代表高位,因此最后的代表的数据应该为
	0000 0010 010 1100 --> 300

对于符号整数,如果值为负数,那么存储数值中的第一位永远为1,若按上面的规则来执行,将永远要用一个很长的字节来存储该数值,即使是-1这么看起来很简单的负数。为达到序列化后的长度与值的绝对值正相关,会对负数进行一定处理,再存储。主要的方式就是将符号整数映射为无符号整数,再按以上规则操作。映射规则为

32位:
(n << 1)^(n >> 31)

64位:
(n <<1 )^(n >> 63)

n位原符号整数的数值,计算效果等同于

if(n<0)
{
	-n*2 -1;
}else
{
	n*2;
}

而该操作只对sint32和sint64类型的数据进行,int32和int64仍是直接序列化。

2、64-bit, 32-bit

这两种比较简单,直接将头部字节后的64/32字节的数据作为原数据,未做任何其他处理

3、length-delimited

对于string或者packed repteated fields等长度未知的数据类型,将以这种方式序列化。
该方式使用第二个字节的值代表存储的长度,例如:

message Test2
{
	optional string b = 2;
}

当b的值为"testing"时候,序列化后的数值为

12 07 [74 65 73 74 69 6e 67]
07 代表后面7个字节为该存储的该类型的数值,即方括号中的值(以UTF8编码)

该序列化方式也用于处理类型嵌套,如:

Message Test3
{
	optional Test1 c = 3;
}

message Test1
{
	optional int32 a = 1;
}

如果c.a的取值为150,那么Test3序列化结果为

1a 03 08 96 01

保存的3个字节的数据正是Test1的序列化结果。

三、参考资料

https://developers.google.com/protocol-buffers/docs/encoding#varints Protocol Buffers官方参考文档

你可能感兴趣的:(数据序列化,开发语言)