简介

encoding/binary 包实现了对数据与 byte 之间的转换,以及 varint 的编解码

编码:

  • func Write(w io.Writer, order ByteOrder, data interface{}) error
  • func PutUvarint(buf []byte, x uint64) int
  • func PutVarint(buf []byte, x int64) int

解码:

  • func Uvarint(buf []byte) (uint64, int)
  • func Varint(buf []byte) (int64, int)
  • func ReadUvarint(r io.ByteReader) (uint64, error)
  • func ReadVarint(r io.ByteReader) (int64, error)

数据的 byte 序列化转换

1
2
3
4
5
6
7
8
// Read从r中读出字节数据并反序列化成结构数据。data必须是固定长的数据值或固定长数据的slice。从r中读出的数据可以使用特殊的字节序来解码,并顺序写入value的字段。当填充结构体时,使用(_)名的字段将被跳过。
func Read(r io.Reader, order ByteOrder, data interface{}) error

// Write将data序列化成字节流写入w中。data必须是固定长度的数据值或固定长数据的slice,或指向此类数据的指针。写入w的字节流可用特殊的字节序来编码。另外,结构体中的(_)名的字段讲忽略。
func Write(w io.Writer, order ByteOrder, data interface{}) error

// Size将返回数据系列化之后的字节长度,数据必须是固定长数据类型、slice和结构体及其指针。
func Size(v interface{}) int

uvarint 和 varint 的编解码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 将uint64类型放入buf中,并返回写入的字节数。如果buf过小,PutUvarint将抛出panic。
func PutUvalint(buf []byte, x uint64) int

// 将int64类型放入buf中,并返回写入的字节数。如果buf过小,PutVarint将抛出panic。
func PutVarint(buf []byte, x int64) int

// 从buf中解码并返回一个uint64的数据,及解码的字节数(>0)。如果出错,则返回数据0和一个小于等于0的字节数n,其意义为:
// 1)n == 0: buf太小
// 2)n < 0: 数据太大,超出uint64最大范围,且-n为已解析字节数
func Uvarint(buf []byte) (uint64, int)

// 从buf中解码并返回一个int64的数据,及解码的字节数(>0).如果出错,则返回数据0和一个小于等于0的字节数n,其意义为:
// 1) n == 0: buf太小
// 2) n < 0: 数据太大,超出64位,且-n为已解析字节数
func Varint(buf []byte) (int64, int)

// 从r中解析并返回一个uint64类型的数据及出现的错误.
func ReadUvarint(r io.ByteReader) (uint64, error)

// 从r中解析并返回一个int64类型的数据及出现的错误.
func ReadVarint(r io.ByteReader) (int64, error)

demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package binary_test

import (
"fmt"
"log"
"bytes"
"encoding/binary"
)

func TestBinary1(t *testing.T) {
var pi float64
b := []byte{0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40}
buf := bytes.NewBuffer(b)
err := binary.Read(buf, binary.LittleEndian, &pi)
if err != nil {
log.Fatalln("binary.Read failed:", err)
}
fmt.Println(pi) // 3.141592653589793
}

func TestBinary2(t *testing.T) {
buf := new(bytes.Buffer)
pi := math.Pi

err := binary.Write(buf, binary.LittleEndian, pi)
if err != nil {
log.Fatalln(err)
}
fmt.Println(buf.Bytes()) // [24 45 68 84 251 33 9 64]
}

func TestBinary3(t *testing.T) {
var a int
p := &a
b := [10]int64{1}
s := "adsa"
bs := make([]byte, 10)

fmt.Println(binary.Size(a)) // -1
fmt.Println(binary.Size(p)) // -1
fmt.Println(binary.Size(b)) // 80
fmt.Println(binary.Size(s)) // -1
fmt.Println(binary.Size(bs)) // 10
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
package binary_test

import (
"encoding/binary"
"fmt"
"strconv"
"testing"
)

func TestBinary(t *testing.T) {
u16 := 1234
sbuf := make([]byte, 4)
ret := binary.PutUvarint(sbuf, uint64(u16))
fmt.Println(ret, len(strconv.Itoa(u16)), sbuf) // 2 4 [210 9 0 0]

u64 := 0x1020304040302010
buf := make([]byte, 10)
ret = binary.PutUvarint(buf, uint64(u64))
// 转成二进制来传输数据,比直接转字符串之后转[]byte这种方式传更节省传输空间
fmt.Println(ret, len(strconv.Itoa(u64)), buf) // 9 19 [144 192 192 129 132 136 140 144 16 0]
}

func TestBinary(t *testing.T) {
i16 := 1234
i64 := -1234567890
buf := make([]byte, 10)
sbuf := make([]byte, 4)

ret := binary.PutVarint(buf, int64(i16))
fmt.Println(ret, len(strconv.Itoa(i16)), sbuf) // 2 4 [0 0 0 0]

ret = binary.PutVarint(buf, int64(i64))
fmt.Println(ret, len(strconv.Itoa(i64)), buf) // 5 11 [163 139 176 153 9 0 0 0 0 0]
}

func TestBinary(t *testing.T) {
sbuf := []byte{}
buf := []byte{144, 192, 192, 132, 136, 140, 144, 16, 0, 1, 1}
bbuf := []byte{144, 192, 192, 129, 132, 136, 140, 144, 192, 192, 1, 1}

num, ret := binary.Uvarint(sbuf)
fmt.Println(num, ret) // 0 0

num, ret = binary.Uvarint(buf)
fmt.Println(num, ret) // 9077982472708112 8

num, ret = binary.Uvarint(bbuf)
fmt.Println(num, ret) // 0 -11
}

func TestBinary(t *testing.T) {
var sbuf []byte
var buf []byte = []byte{144, 192, 192, 129, 132, 136, 140, 144, 16, 0, 1, 1}
var bbuf []byte = []byte{144, 192, 192, 129, 132, 136, 140, 144, 192, 192, 1, 1}

num, ret := binary.Varint(sbuf)
fmt.Println(num, ret) //0 0

num, ret = binary.Varint(buf)
fmt.Println(num, ret) //580990878187261960 9

num, ret = binary.Varint(bbuf)
fmt.Println(num, ret) //0 -11
}

func TestBinary(t *testing.T) {
var sbuf []byte
var buf []byte = []byte{144, 192, 192, 129, 132, 136, 140, 144, 16, 0, 1, 1}
var bbuf []byte = []byte{144, 192, 192, 129, 132, 136, 140, 144, 192, 192, 1, 1}

num, err := binary.ReadUvarint(bytes.NewBuffer(sbuf))
fmt.Println(num, err) //0 EOF

num, err = binary.ReadUvarint(bytes.NewBuffer(buf))
fmt.Println(num, err) //1161981756374523920 <nil>

num, err = binary.ReadUvarint(bytes.NewBuffer(bbuf))
fmt.Println(num, err) //4620746270195064848 binary: varint overflows a 64-bit integer
}

func TestBinary(t *testing.T) {
var sbuf []byte
var buf []byte = []byte{144, 192, 192, 129, 132, 136, 140, 144, 16, 0, 1, 1}
var bbuf []byte = []byte{144, 192, 192, 129, 132, 136, 140, 144, 192, 192, 1, 1}

num, err := binary.ReadVarint(bytes.NewBuffer(sbuf))
fmt.Println(num, err) //0 EOF

num, err = binary.ReadVarint(bytes.NewBuffer(buf))
fmt.Println(num, err) //580990878187261960 <nil>

num, err = binary.ReadVarint(bytes.NewBuffer(bbuf))
fmt.Println(num, err) //2310373135097532424 binary: varint overflows a 64-bit integer
}