什么是Varint
varint是一种对整型进行压缩的编码格式,大量用于Google的ProtocolBuffers中。
每个字节第一位表示标志位,剩余7位存储数据,除了末尾字节外其他字节标志位都是1.
且字节顺序采用了小端序.
示例说明
比如int32类型的234
二进制为:1110 1010
小端序7位: 110 1010 000 0001
加上标志位:1110 1010 0000 0001
int32 | 32 | |||||||||||||||
二进制 | 1 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | ||||||||
varint | 1 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
优缺点
以int32为例,一般来说小数使用较为频繁.对于小数,可以用1、2个字节存储,相较于原先的4个字节,能大大的减少空间占用。
但是对于负数,由于第一位符号位是1,在varint编码时会将其视作很大的正整数,编码结果始终会占用10个字节,没有达到压缩的效果,针对负数可使用ZigZag。
代码实现
编码
public static int MAX_VARINT32_SIZE = 5;
public static byte[] encode32(int num) {
byte[] buf = new byte[MAX_VARINT32_SIZE];
int i = 0;
//大于127,需要2个以上字节存储
for (; num > 127; i++) {
//1.0x7f 十进制127,二进制表示7个1,&0x7f表示每次取低7位
//2.最高位为msb,标志位为1,表示当前字节不是最后一个字节
//3.右移7位
buf[i] = (byte) (0x80 | (num & 0x7f));
num >>= 7;
}
//处理最后一个字节
buf[i++] = (byte) num;
return Arrays.copyOfRange(buf, 0, i);
}
解码
public static int decode32(byte[] buf) {
int num = 0;
for (int i = buf.length - 1, shift = 7; i >= 0; i--, shift += 7) {
//因为是小端序,从末尾开始,每次取该字节的低7位,
// 处理完之后向高位移动7位(左移7位),当处理到字节数组第一位时,不用移动
num |= (buf[i] & 0x7f);
if (i != 0) {
num <<= shift;
}
}
return num;
}