什么是Varint编码

Varint是一种使用一个或多个字节序列化整数的方法,会把整数编码为变长字节。对于32位整型数据经过Varint编码后需要1~5个字节,小的数字使用1个byte,大的数字使用5个bytes。64位整型数据编码后占用1~10个字节。在实际场景中小数字的使用率远远多于大数字,因此通过Varint编码对于大部分场景都可以起到很好的压缩效果。

编码原理

除了最后一个字节外,varint编码中的每个字节都设置了最高有效位(most significant bit - msb)–msb为1则表明后面的字节还是属于当前数据的,如果是0那么这是当前数据的最后一个字节数据。每个字节的低7位用于以7位为一组存储数字的二进制补码表示,最低有效组在前,或者叫最低有效字节在前。这表明varint编码后数据的字节是按照小端序排列的。

关于字节排列的方式引用一下维基百科上的词条

字节的排列方式有两个通用规则。例如,一个多位的整数,按照存储地址从低到高排序的字节中,如果该整数的最低有效字节(类似于最低有效位)在最高有效字节的前面,则称小端序;反之则称大端序。在网络应用中,字节序是一个必须被考虑的因素,因为不同机器类型可能采用不同标准的字节序,所以均按照网络标准转化。

通俗一点说就是:大端序是按照数字的书写顺序排列的,而小端序是颠倒书写顺序进行排列的。

看下面的图示会更好理解一些

图中对数字123456进行varint编码,123456用二进制表示为1 11100010 01000000,每次低从向高取7位再加上最高有效位变成1100 0000 11000100 00000111 所以经过varint编码后123456占用三个字节分别为192 196 7

解码的过程就是将字节依次取出,去掉最高有效位,因为是小端排序所以先解码的字节要放在低位,之后解码出来的二进制位继续放在之前已经解码出来的二进制的高位最后转换为10进制数完成varint编码的解码过程。

编码实现

由于protocol buffer中大量使用了varint编码,我从github.com/golang/protobuf/proto库中找到了对数据进行varint编解码的Go语言实现方法,实现代码中用位运算完成了上面说的varint编码过程。

const maxVarintBytes = 10 // maximum length of a varint// 返回Varint类型编码后的字节流
func EncodeVarint(x uint64) []byte {var buf [maxVarintBytes]bytevar n int// 下面的编码规则需要详细理解:// 1.每个字节的最高位是保留位, 如果是1说明后面的字节还是属于当前数据的,如果是0,那么这是当前数据的最后一个字节数据//  看下面代码,因为一个字节最高位是保留位,那么这个字节中只有下面7bits可以保存数据//  所以,如果x>127,那么说明这个数据还需大于一个字节保存,所以当前字节最高位是1,看下面的buf[n] = 0x80 | ...//  0x80说明将这个字节最高位置为1, 后面的x&0x7F是取得x的低7位数据, 那么0x80 | uint8(x&0x7F)整体的意思就是//  这个字节最高位是1表示这不是最后一个字节,后面7为是正式数据! 注意操作下一个字节之前需要将x>>=7// 2.看如果x<=127那么说明x现在使用7bits可以表示了,那么最高位没有必要是1,直接是0就ok!所以最后直接是buf[n] = uint8(x)//// 如果数据大于一个字节(127是一个字节最大数据), 那么继续, 即: 需要在最高位加上1for n = 0; x > 127; n++ {// x&0x7F表示取出下7bit数据, 0x80表示在最高位加上1buf[n] = 0x80 | uint8(x&0x7F)// 右移7位, 继续后面的数据处理x >>= 7}// 最后一个字节数据buf[n] = uint8(x)n++return buf[0:n]
}
  • 0x7F的二进制表示是0111 1111 ,所以x & 0x7F 与操作时,得到x二进制表示的最后7个bit位(前面的bit位通过与0做位与运算都被舍弃了)
  • 0x80 的二进制表示是 1000 0000 ,所以 0x80 | uint8(x&0x7F)是在取出的x的后7个bit位前加上1(msb)

解码实现

解码就是编码的逆过程,同样是用位运算就能快速有效的完成解码,结合下面的代码注释再在纸上推演一遍理解起来就不难了。

func DecodeVarint(buf []byte) (x uint64, n int) {for shift := uint(0); shift < 64; shift += 7 {if n >= len(buf) {return 0, 0}b := uint64(buf[n])n++// 下面这个分成三步走:// 1: b & 0x7F 获取下7bits有效数据// 2: (b & 0x7F) << shift 由于是小端序, 所以每次处理一个Byte数据, 都需要向高位移动7bits// 3: 将数据x和当前的这个字节数据 | 在一起x |= (b & 0x7F) << shiftif (b & 0x80) == 0 {return x, n}}// The number is too large to represent in a 64-bit value.return 0, 0
}

Playground

到这里varint的编解码过程就都搞懂了,理解了varint编码原理后再看protocol buffer的编码原理就会容易很多。

详解varint编码原理相关推荐

  1. FFmpeg入门详解--音视频原理及应用:梅会东:清华大学出版社

    大家好,我的第一本书正式出版了,可以在京东各大店铺抢购哦. <FFmpeg入门详解--音视频原理及应用:梅会东:清华大学出版社> 京东自营链接:https://item.jd.com/13 ...

  2. 详解one-hot编码及代码举例

    1.什么是Onehot编码? onehot编码又叫独热编码,其为一位有效编码,主要是采用N位状态寄存器来对N个状态进行编码,每个状态都由他独立的寄存器位,并且在任意时候只有一位有效.          ...

  3. 【转详解步进电机工作原理】

    详解步进电机工作原理[转自知乎gk-auto] 步进电机是将电脉冲信号转变为角位移或线位移的开环控制元件.在非超载的情况下,电机的转速.停止的位置只取决于脉冲信号的频率和脉冲数,而不受负载变化的影响, ...

  4. 初级游戏外挂编程详解 windows运行原理+游戏辅助编程 游戏外挂编程

    @TOC初级游戏外挂编程详解 windows运行原理+游戏辅助编程 游戏外挂编程 [1]什么是windows API Windows API 中文翻译过来就是windows应用程序接口(Applica ...

  5. 多维度详解redis以及原理实现,结构与应用分析

    6个方面了解redis应用及其实现原理 1.redis数据存储概述 2.string结构以及应用 3.list结构以及应用 4.hash结构以及应用 5.set结构以及应用 6.zset结构以及应用 ...

  6. 详解帧中继工作原理及作用

    详解帧中继工作原理及作用 帧中继特点 帧中继工作原理 帧中继的作用 帧中继习题 帧中继(FrameRelay)是一种用于连接计算机系统的面向分组的通信方法.它主要用在公共或专用网上的局域网互联以及广域 ...

  7. ArrayList 扩容详解,扩容原理

    ArrayList 扩容详解,扩容原理 ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长. ArrayList不是线程安全的,只能用在单线程环境下. 实现了Serializable ...

  8. iOS runtime 底层详解、内部原理、场景应用

    前言学:位域和共用体 一:isa指针--runtime之前的学习 1.1:苹果应用的按位或.按位与 二:类对象信息 2.1:类对象信息:rw_t 2.2:类对象信息:方法缓存(很关键) 2.2:类对象 ...

  9. 【Servlet】Servlet 详解(使用+原理)

    文章目录 1. Servlet 介绍 1.1 什么是 Servlet 1.2 Servlet 的主要工作 2. Servlet 程序创建步骤 2.1 创建项目 2.2 引入依赖 2.3 创建目录 2. ...

最新文章

  1. Mozilla公布WebVR API标准草案
  2. AI一分钟 | 谷歌租下北京 6000 平米写字楼,或将发展AI项目;工信部就个人信息保护约谈百度、支付宝、今日头条
  3. SLAM综述-Lidar SLAM
  4. HW2017笔试编程题
  5. couchdb java 连接_CouchDB客户端连接的说明---Java版
  6. 【转】Oracle回收站(recyclebin)
  7. Linux启动shell的快捷方式,Linux下为可执行shell脚本文件(.sh),制作桌面启动快捷方式...
  8. 下周开幕!给深圳的嵌入式和电子工程师准备的嘉年华来了
  9. pytorch 中nn.MaxPool1d() 和nn.MaxPool2d()对比
  10. 小程序input聚焦事件_详解小程序input框失焦事件在提交事件前的处理
  11. Ng Alain分页控件的使用
  12. 开发基于 Google Map 的 Android 应用
  13. CTF万里追踪——图片里的秘密
  14. url地址栏传json格式数据参数
  15. Windows桌面图标和分类美化小工具
  16. 模型描边(二)—— three.js着色器法线延伸
  17. 富士施乐Fuji Xerox Phaser 6700 驱动
  18. libfranka---joint_impendence_control例程分析
  19. 石家庄计算机职业学院是本科吗,石家庄信息工程职业学院是本科还是专科?
  20. 云服务器布置_如何选择正确的云服务器配置?

热门文章

  1. 关于Spring Cloud Commons—普通抽象
  2. SUPERSET使用笔记
  3. iOS 权限判断 跳转对应设置界面
  4. 状压DP UVA 10817 Headmaster's Headache
  5. 【翻译】Sencha Cmd中脚本压缩方法之比较
  6. strtok_r实现方式之一
  7. 由通知栏进入到应用的尝试
  8. 关于在虚拟机上进行wp7的开发
  9. Object Detection: Face Detection using Haar Cascades
  10. 20180828 上课截图