protobuf 之 Varint

3 篇文章 0 订阅
2 篇文章 0 订阅

varint 背景

Varint 是一种紧凑的表示数字的方法。它用一个或多个字节来表示一个数字,值越小的数字使用越少的字节数。这能减少用来表示数字的字节数。
Varint 中的每个 byte 的最高位 bit 有特殊的含义,如果该位为 1,表示后续的 byte 也是该数字的一部分,如果该位为 0,则结束。其他的 7 个 bit 都用来表示数字。
如下图:(注意到最终计算前将两个 byte 的位置相互交换过一次,这是因为 Google Protocol Buffer 字节序采用 little-endian 的方式)
图片

举例

例如:
1、整数 300 的表示,需要两个字节:
1010 1100 0000 0010

2、整数 1 的表示,仅需一个字节:
0000 0001

占用字节数

采用 Varint,对于小的 int32 类型数字,可以用 1 个 byte 来表示;但是也有不好的一面,对于大数字来说依旧采用 Varint 表示法时,大到会需要 5 个 byte 来表示。
所以用 Varint 表示 int32 数字,占 1~ 5 Byte。如下:

int32 MAX 0111 1111 1111 1111 1111 1111 1111 1111

Varint32 1111 1111 1111 1111 1111 1111 1111 1111 0000 0111

即使如此从统计的角度来说,一般不会所有的消息中的数字都是大数,因此大多数情况下,采用 Varint 后,可以用更少的字节数来表示数字信息。

使用注意:

1、写Varint时,可以不关注占用的字节长度范围
2、读取Varint时,必须以最大长度来读取解析。否则内部解析Varint数据时会越界 ( 比如:数据实际占用了3个字节,但是你只读2个字节来解析数据时,第二个字节并非数据末尾字节,proto 库函数会继续解析直到遇到末尾标志。但是在库函数继续解析时会发生越界)

举例 Varint 的读写

eg: cpp 写 Varint

// cpp
	std::ofstream output;
	output.open("tmp.log");
	/*
	*** 此处忽略 n 行无关代码
	*/
	{
        google::protobuf::io::OstreamOutputStream raw_output(&output);
		google::protobuf::io::CodedOutputStream coded_output(&raw_output);
        
		auto user_data = response->userdata();// 简略: response 为proto格式
        int fid = (int)user_data;
        coded_output.WriteVarint32(fid); // 文件中写入 varint32 类型 id 数据
        coded_output.WriteVarint32(response->ByteSizeLong());// 文件中写入 varint32 类型 response 长度
        response->SerializeToCodedStream(&coded_output);// 文件中写入 response 数据
	}

eg:python 读 varint

# python

	# 忽略 n 行无关代码
	
	fid_buf = file.read(5) # 读取文件5个字节
    if not fid_buf:
          return -1, None

    fid, new_pos = _DecodeVarint32(fid_buf, 0) #从5个字节中获取fid,并返回实际Varint占用长度
    offset = len(fid_buf) - new_pos
    
    if offset != 0:
        file.seek(-offset, 1)

    buf = file.read(5) # 再读取文件5个字节
    if not buf:
        return -1, None
    msg_len, new_pos = _DecodeVarint32(buf, 0) #从5个字节中获取 response 长度,并返回实际Varint占用长度
	
    msg_buf = file.read(msg_len)# 读取 response 

  • 16
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值