Golang中encoding/binary包的应用

介绍

golang的binary包简单实现了数字(number)到字节序(byte sequences)的转换,以及64位整型(varint)的编码与解码。

首先简单看一下binary的结构与方法
在这里插入图片描述

理解字节序(Byte sequences)、大字端(Big Endian)、小字端(Little Endian)

字节序,即字节在电脑中存放时的序列与输入(输出)时的序列是先到的在前还是后到的在前。包含大字端与小字节端

在这里插入图片描述
一个内存地址能存储1 byte的数据

大字端:按照低地址位到高地址位的顺序存放高字节到低字节,既高字节在前,低字节在后。
小字端:与大字端相反,按照低地址位到高地址位的顺序存放低字节到高字节,既低字节在前,高字节在后。

看这个文字描述比较晦涩难懂,下面举个例子

eg.
那一个64位10进制int数287454020举例子,正好对应16进制的0x11223344,那么用一个byte数组存储的方式如下

在这里插入图片描述

内存地址0x000000010x000000020x000000030x00000004
Big Endian11223344
Little Endian44332211

绝大部分CPU都是按照Little Endian方式存储数据的,但是用于网络传输的时候大部门是使用Big Endian方式作为数据传输的。

	//定义一个长整型16进制数0x11223344,也就是10进制的287454020
	num := int64(0x1122334455667788)

	//声明两个Writer的实现buffer,长度8,因为长整型int是64位,也就是8字节
	bigEndianBuffer := bytes.NewBuffer(make([]byte, 0))
	littleEndianBuffer := bytes.NewBuffer(make([]byte, 0))
	//将变量写入流中 一个使用高字端,一个使用低字端
	_ = binary.Write(bigEndianBuffer, binary.BigEndian, num)
	_ = binary.Write(littleEndianBuffer, binary.LittleEndian, num)
	
	fmt.Println(bigEndianBuffer.Bytes())
	//[17 34 51 68 85 102 119 136] 其实对应的16进制就是
	//[0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88]

	fmt.Println(littleEndianBuffer.Bytes())
	//[136 119 102 85 68 51 34 17] 与上面结果正好相反,对应的16进制就是
	//[0x88 0x77 0x66 0x55 0x44 0x33 0x22 0x11]

可变长度编码(Variable-length encoding)

可变长度整数(以下简称为varint)压缩算法是将整数压缩成比通常需要的更小空间的一种方法。一个varint算法以用一个字节表示10,而用4个字节来表示8亿。

比如,在应用中,大多数的值都在0到100之间,而有些值可能会超过16384,如果使用固定长度的空间来表示这些值的话,就需要一个完整的32位整数,即使大多数值用单个字节来表示就够了。

正是因为在中大多数数字的分布并不均匀,varint算法才有了用武之地。通常情况下,较小的数字出现的概率大于较大的数字。varint算法作出的权衡是,用较小的空间存储小数字,而用较大的空间存储大数字。因此,采用这种算法来对整数进行编码是有意义的,它可以节省存储数据需要的空间或者传输数据时所需的带宽。

两种varint编码的常见方式是使用前缀长度和使用连续位标识。

连续位标识

varint算法与Protobuf的一致,Protobuf用的是连续位标识技术,使用每个字节的第一位来标识是否需要继续向后读。每个字节低7位用于实际的编码。

比如对于数字25,8位二进制为0001 1001。注意最左边一位是0,在Protobuf中,这意味着不需要继续向后读了。采用这样的技术,0到127之间的数字都可以用一个字节表示。

对于大于127的数,比如225,二进制为1110 0001,如果用7个bit进行编码,则得到两个分组000 0001和110 0001。对Protobuf来说,最不重要的分组首先出现,这意味着应该向低阶组添加一个连续位0 000 0001和1 110 0001。逆置分组后,得到1110 0001和0000 0001。这样就使用两个字节对225进行了编码。

解码的过程如下,先读一个字节,如果该字节的高位第一个bit为1,则继续读;如果为0,则停止。移除每个字节的第一个bit,逆置剩余的bit分组,重新组合后得到原始的数据。

还是以225为例。

  • 读取到的字节为11100001和00000001。
  • 移除首bit后得到11000001和0000001。
  • 逆置后得到0000001和1100001。
  • 得到11100001,即为225。

这个技术非常强大,它可以编码任意大小的数字。

binary包下的函数 putVarint() 和 putUvarint() 把可变长值写到内存字节切片中。

这两个函数把 x 编码到 buf 中并返回写入 buf 中字节的长度,如果 buf 初始化长度过小(比 x 还要小)函数就会 panic , 建议使用 binary.MaxVarintLen64 常量确保出现 panic 的情况。

变量

binary.BigEndian:对应以大字端方式
binary.LittleEndian:对应以小字端方式
binary.MaxVarintLen16、binary.MaxVarintLen32、binary.MaxVarintLen64: 可变长度编码建议初始化的byte切面长度

用于binary的相关方法作为存储方式的参数。

方法

Read:按照指定的字节序读取数据流(io.Reader)到一个指针变量。
Write:按照指定的字节序将指针变量写入数据流(io.Wrter)中。
PutUvarint:解码无符号的Varint(64位uint)
PutVarint:解码Varint(64位int)
Uvarint:编码无符号的Varint(64位uint)
Varint:编码Varint(64位int)

https://www.jianshu.com/p/a52c16fca39e
https://blog.csdn.net/qq_31967569/article/details/82689039

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值