[TOC] ## binary.Size 获取结构体的大小 固定大小的结构体,就要求结构体中不能出现\[\]byte这样的切片成员,否则Size返回-1,且不能进行正常的序列化操作 <details> <summary>code</summary> ``` a0 := 123 // or a0 := "123" fmt.Printf("a0 : %d \n", binary.Size(a0)) // -1 a1 := int16(123) fmt.Printf("a1 : %d \n", binary.Size(a1)) // 2 a2 := uint16(123) fmt.Printf("a2 : %d \n", binary.Size(a2)) // 2 a3 := uint32(123) fmt.Printf("a3 : %d \n", binary.Size(a3)) // 4 a4 := uint64(123) fmt.Printf("a4 : %d \n", binary.Size(a4)) // 8 type b struct { b1 uint16 b2 uint32 } var B b fmt.Printf("B : %d \n", binary.Size(B)) //6 B.b1 = uint16(32) fmt.Printf("B : %d \n", binary.Size(B)) //6 ``` </details> <br/> ## 小端序与大端序 序列化 ``` a :=int32(65535) b :=int32(65535) buf :=new(bytes.Buffer) binary.Write(buf,binary.LittleEndian,a) fmt.Printf("%+v\n", buf.Bytes()) // [255 255 0 0] buf2 :=new(bytes.Buffer) binary.Write(buf2,binary.BigEndian,b) fmt.Printf("%+v\n", buf2.Bytes()) // [0 0 255 255] ``` > 结构体也可同理实现小端序,大端序的序列化 ## 结构体转为序列化 ``` type A struct { One int32 Two int32 } var a A a.One = int32(1) a.Two = int32(3) fmt.Println("a's size is ", binary.Size(a)) // 8 buf := new(bytes.Buffer) binary.Write(buf, binary.LittleEndian, a) fmt.Println("after write ,buf is:", buf.Bytes()) //[1 0 0 0 3 0 0 0] ``` 1. 这里采用了小端序的方式进行序列化(x86架构都是小端序,网络字节序是大端序) 2. 对于结构体中得“_”成员不进行序列化 3. 结构体中不能出现\[\]byte这样的切片成员,否则Size返回-1 ## 序列化转结构体 从buf中反序列化回一个结构 ``` type A struct { One uint16 Two int32 } var aa A aa.One=65535 var bb A buf := new(bytes.Buffer) binary.Write(buf,binary.LittleEndian,aa) //序列化 binary.Read(buf,binary.LittleEndian,&bb) //反序列化 fmt.Printf("%+v\n", bb) //{One:65535 Two:0} ``` > 只有多于一位的才需要指定大端序 ## 编码字节切片 ``` // write v := uint32(500) buf := make([]byte,4) //需大于4位, 过小 抛出异常 index out of range [3] with length 3 binary.BigEndian.PutUint32(buf, v) // read x := binary.BigEndian.Uint32(buf) fmt.Printf("%+v\n", x) ``` ## 流处理 读写固定长度值的流 (stream) Read 通过指定类型的字节序把字节解码 (decode) 到 data 变量中。解码布尔类型时,0 字节 (也就是 `[]byte{0x00` ) 为 false, 其他都为 true Read ``` func main() { var( piVar float64 boolVar bool ) piByte := []byte{0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40} boolByte := []byte{0x00} piBuffer := bytes.NewReader(piByte) boolBuffer := bytes.NewReader(boolByte) binary.Read(piBuffer, binary.LittleEndian, &piVar) binary.Read(boolBuffer, binary.LittleEndian, & boolByte) fmt.Println("pi", piVar) // pi 3.141592653589793 fmt.Println("bool", boolVar) // bool false } ``` Write ``` func main() { buf := new(bytes.Buffer) var pi float64 = math.Pi err := binary.Write(buf, binary.LittleEndian, pi) if err != nil { fmt.Println("binary.Write failed:", err) } fmt.Printf("% x", buf.Bytes()) // 18 2d 44 54 fb 21 09 40 } ``` 在实际编码中,面对复杂的数据结构,可考虑使用更标准化高效的协议,比如[Protocol Buffer](https://link.zhihu.com/?target=https%3A//developers.google.com/protocol-buffers/) ## 包头定义的例子 ``` type Head struct { Cmd byte Version byte Magic uint16 Reserve byte HeadLen byte BodyLen uint16 } func NewHead(buf []byte)*Head{ head := new(Head) head.Cmd = buf[0] head.Version = buf[1] head.Magic = binary.BigEndian.Uint16(buf[2:4]) // 只有多余一位的才需要指定大端序 head.Reserve = buf[4] head.HeadLen = buf[5] head.BodyLen = binary.BigEndian.Uint16(buf[6:8]) return head } ```