相关文章推荐
非常酷的可乐  ·  姜平同志担任南京农业大学动物医学院院长-南京 ...·  1 周前    · 
有胆有识的高山  ·  在华22年仅一个项目存活 ...·  10 月前    · 
想旅行的太阳  ·  【SAIF金融E沙龙】变局下的全球治理新思维 ...·  10 月前    · 
腼腆的针织衫  ·  这壶黄芩茶 ...·  1 年前    · 
文质彬彬的椰子  ·  有大佬知道艺美娃娃论坛吗? - 知乎·  1 年前    · 
Code  ›  protobuf编码和存储方式详解_protobuf bytes类型数据存取_~青萍之末~的博客
protobuf 编码转换 二进制 protobuf数据类型
https://blog.csdn.net/daaikuaichuan/article/details/105639884
乐观的青蛙
2 年前
  • 一、消息结构
  • 二、Wire Type = 0时的编码和存储方式
    • 2.1 编码方式
      • 2.1.1 Varints编码
      • 2.1.2 ZigZag编码
    • 2.2 存储方式
  • 三、Wire Type = 2时的编码和存储方式
    • 3.1 编码方式
    • 3.2 存储方式
  • 四、Wire Type = 1&5时的编码和存储方式
    • 4.1 编码方式
    • 4.2 存储方式

    一、消息结构

    【 结论先行 】:

    • protobuf将消息里的每个字段进行 编码 后,再利用 T-L-V或者T-V的方式进行数据存储 。
    • protobuf对于 不同类型的数据会使用不同的编码和存储方式 。
    • protobuf的 编码和存储方式是其性能优越、数据体积小的原因 。

    protobuf中每一个消息中的字段都是 key-value类型 ,序列化的时候 key-value被编码和存储为字节流 , 整体的消息结构如下图所示:
    在这里插入图片描述
    Tag 由字段编号 field_number 和 编码类型 wire_type 组成, Tag 整体采用 Varints 编码。Tag的值为(field_number << 3) | wire_type,即 最后三位存储wire type (编码类型), 其他位用于存储field number (字段编号)。
    在这里插入图片描述
    wire type编码有以下几种类型:
    在这里插入图片描述
    【T-L-V格式】:

    • T 作为标识号表明了在message中的位置以及数据类型。

    • L 定义了value的长度,表示可变长度的字段。

    • V 表示实际的value。

    二、Wire Type = 0时的编码和存储方式

    【 结论先行 】:对于 int32/int64 类型的数据(正数),protobuf会使用 Varints编码 ;而对于 sint32/sint64 类型的数据(负数),protobuf会 先使用ZigZag 编码,再使用Varints编码 。 存储格式为Tag-Value 。

    2.1 编码方式

    2.1.1 Varints编码

    Varints是使用一个或多个字节序列化整数的一种方法,也是一种 压缩算法 。 在Varints编码方式中,数字越小,占用的字节越少 。Varints编码的主要依据是: 越小的数字出现的频率越高 。

    通常我们要存储一个整数需要4个字节或者8个字节,例如对于32位整数300,其二进制表示为: 00000000 00000000 00000001 00101100 。可以看到二进制表示中有很多无用的0也占用了内存,因此可以使用Varints编码对其进行压缩和解码。

    Varints编码 使用msb表示当前是否是最后一个字节 ,如果 msb为1表示后面还有字节,如果msb为0表示当前字节是最后一个字节 。因为加入了msb,所以 每一个字节低七位表示具体的数值 。

    【 Varints编码过程如下 】:

    1. 先将整数转换为不带前导0的二进制表示: 100101100 。
    2. 每一个字节的低七位存储数值: 0000010 0101100 。
    3. 转换为小端模式: 0101100 0000010 。
    4. 添加msb标志位: 10101100 00000010 。

    从上述编码过程可知,原来需要四个字节表示的整数经过编码后只需要两个字节即可存储。Varints编码由于使用了msb标志位,因此可以表示的最大整数为2^28,所以说Varints编码基本可以满足绝大多数的应用场景。

    2.1.2 ZigZag编码

    Varints的不足在于对负数进行编码时效率极低 ,因为负数的二进制表示中1特别多,所以没办法去掉前导0,所以使用Varints编码意义不大。ZigZag编码被用来解决这一问题, 其核心思想是将有符号整数转换为无符号整数,进而能够使用Varints编码 。 如下图所示:
    在这里插入图片描述
    以负数-11为例,其二进制在计算机中是用补码表示的,整数原码为: 00001011 ,反码为: 11110100 ,补码(反码加1)为: 11110101 。

    【 ZigZag编码过程如下 】:

    1. 原数左移一位(左移时丢弃最高位,低位补0): 11101010 。
    2. 原数右移31位(右移时符号位不变,高位补符号位): 11111111 。
    3. 将上述两个二进制数取异或: 00010101 。

    ZigZag编码和解码过程用代码表示为:

    int int_to_zigzag(int n)
    	return (n <<1) ^ (n >>31);
    int zigzag_to_int(int n) 
    	return (((unsignedint)n) >>1) ^ -(n & 1);
    

    2.2 存储方式

      protobuf使用Varints和ZigZag编码后,以T-V格式存储数据,即:
    在这里插入图片描述

    三、Wire Type = 2时的编码和存储方式

      【结论先行】:对于string,bytes和嵌套消息类型的数据,protobuf会使用Length-delimited编码,存储格式为Tag-Length-Value。

    3.1 编码方式

      当时value的类型为string,bytes和嵌套消息时,protobuf使用Length-delimited编码,即将value的length也编码进最终数据。
    例如:

    message Test2 {
      required string b = 2;
    // 设置b的值为"testing",则编码之后为:
    12 07 74 65 73 74 69 6e 67
    

    3.2 存储方式

      使用Length-delimited编码时的数据存储方式为T-L-V,即:
    在这里插入图片描述

    四、Wire Type = 1&5时的编码和存储方式

      【结论先行】:对于大整数类型的数据,protobuf会使用64-bit和32-bit编码方式,存储格式为Tag-Value。

    4.1 编码方式

      Varints适合处理一定范围内的数字,当数字很大的时候使用Varints编码效率反而很低,因此protobuf定义了64-bit和32-bit两种定长编码类型,即:
    在这里插入图片描述

    4.2 存储方式

      protobuf使用64-bit和32-bit编码后,以T-V格式存储数据。

    参考:
    https://developers.google.cn/protocol-buffers/docs/encoding
    https://www.bilibili.com/video/BV1Bt411X73L/?spm_id_from=333.788.videocard.19
    https://www.cnblogs.com/mler/p/10252886.html
    https://www.jianshu.com/p/30ef9b3780d9
    https://www.jianshu.com/p/6dd2fd0362b8

    文章目录一、消息结构二、Wire Type = 0时的编码和存储方式2.1 编码方式2.1.1 Varints编码2.1.2 ZigZag编码2.2 存储方式三、Wire Type = 2时的编码和存储方式3.1 编码方式3.2 存储方式四、Wire Type = 1&amp;5时的编码和存储方式4.1 编码方式4.2 存储方式一、消息结构【结论先行】:protobuf将消息里的每个字段进...
    protobuf提供了多种基础数据格式,包括string/bytes。从字面意义上,我们了解bytes适用于任意的二进制字节序列。然而对C++程序员来讲,std::string既能存储ASCII文本字符串,也能存储任意多个\0的二进制序列。那么区别在哪里呢? 同时在实际使用中,我们偶尔会看到类似这样的运行错误:
    Protobuf介绍 Protobuf (Protocol Buffers) 是谷歌开发的一款无关平台,无关语言,可扩展,轻量级高效的序列化结构的数据格式,用于将自定义数据结构序列化成字节流,和将字节流反序列化为数据结构。所以很适合做数据存储和为不同语言,不同应用之间互相通信的数据交换格式,只要实现相同的协议格式,即后缀为proto文件被编译成不同的语言版本,加入各自的项目中,这样不同的语言可以解析其它语言通过Protobuf序列化的数据。目前官方提供c++,java,go等语言支持。 下面表格是支持语言的
    return max; //编译中max可以换成别的定义,但要注意你弟你定义的变量一定要初始化,通常,我们遇到加号时,定义为0,遇到乘号时,定义为1,具体原因就不做解释,学过数学的应该都能理解。 1、json: 一般的web项目中,最流行的主要还是json。因为浏览器对于json数据支持非常好,有很多内建的函数支持。 2、xml: 在webservice中应用最为广泛,但是相比于json,它的数据更加冗余,因为需要成对的闭合标签。json使用了键值对的方式,不仅压缩了一定的数据空间,同时也具有可读性。 3、protobuf:是后起之秀,是谷歌开源的一种数据格式,适合高性能,对响应速度有要求的数据传输场景。因为profobuf是二进制数据格式,需要编码和解码。数据本身不具有可读
    在很多很多时候被问起,为什么选择protobuf?最先被想起的回答的就是体积小、解析快。那相比较于json、XML,为什么protobuf能够做到又小又快呢? 归其原因,这与它的编解码方式有很大的关系。本文将走进protobuf的深层原理来进行剖析。 本文针对实际的例子,来对protobuf的编解码方式进行详细讲解。其中,.proto文件定义如下: syntax = "proto2";
    博客搬家,原地址:https://langzi989.github.io/2017/06/07/protoBuffer中string与byte类型区别/ 从上一节protobuffer的介绍中我们知道字符串类型在protobuffer中有string和bytes两种类型,那这两种类型有什么区别呢,什么时候用string,什么时候用bytes。在C++中两种类型分别对应的是什么类型.下面将揭开迷雾
 
推荐文章
非常酷的可乐  ·  姜平同志担任南京农业大学动物医学院院长-南京农业大学动物医学院
1 周前
有胆有识的高山  ·  在华22年仅一个项目存活 格莱珉银行模式水土不服_手机新浪网
10 月前
想旅行的太阳  ·  【SAIF金融E沙龙】变局下的全球治理新思维——简世勋《世界不是平的》新书分享会—5月17日/北京 - 活动预告 - 上海高级金融学院(SAIF)|中国的世界级金融学院
10 月前
腼腆的针织衫  ·  这壶黄芩茶 高平张永新一“泡”就是12年_高平市人民政府网
1 年前
文质彬彬的椰子  ·  有大佬知道艺美娃娃论坛吗? - 知乎
1 年前
今天看啥   ·   Py中国   ·   codingpro   ·   小百科   ·   link之家   ·   卧龙AI搜索
删除内容请联系邮箱 2879853325@qq.com
Code - 代码工具平台
© 2024 ~ 沪ICP备11025650号