Golang二进制流打包与解包:binpacker库使用指南
binpacker是一个轻量级的Golang库,用于方便地进行二进制数据的打包与解包操作。它提供了简单的API来处理各种基本数据类型的二进制序列化。
安装
go get github.com/zhuangsirui/binpacker
基本用法
1. 打包数据
package main
import (
"bytes"
"fmt"
"github.com/zhuangsirui/binpacker"
)
func main() {
buffer := new(bytes.Buffer)
packer := binpacker.NewPacker(buffer)
// 打包不同类型的数据
err := packer.PushUint16(12345) // 2字节
err = packer.PushString("hello") // 字符串
err = packer.PushFloat32(3.14) // 4字节浮点数
err = packer.PushBool(true) // 1字节布尔值
if err != nil {
fmt.Println("打包出错:", err)
return
}
// 获取打包后的二进制数据
binData := buffer.Bytes()
fmt.Printf("打包后的数据: %x\n", binData)
}
2. 解包数据
package main
import (
"bytes"
"fmt"
"github.com/zhuangsirui/binpacker"
)
func main() {
// 假设这是接收到的二进制数据
binData := []byte{0x30, 0x39, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0xc3, 0xf5, 0x48, 0x40, 0x01}
buffer := bytes.NewBuffer(binData)
unpacker := binpacker.NewUnpacker(buffer)
// 按打包顺序解包
var num uint16
var str string
var pi float32
var flag bool
err := unpacker.ShiftUint16(&num)
err = unpacker.ShiftString(&str)
err = unpacker.ShiftFloat32(&pi)
err = unpacker.ShiftBool(&flag)
if err != nil {
fmt.Println("解包出错:", err)
return
}
fmt.Printf("解包结果: %d, %s, %f, %t\n", num, str, pi, flag)
}
支持的数据类型
binpacker支持以下数据类型的打包与解包:
- 整数:
PushInt8/16/32/64
, ShiftInt8/16/32/64
- 无符号整数:
PushUint8/16/32/64
, ShiftUint8/16/32/64
- 浮点数:
PushFloat32/64
, ShiftFloat32/64
- 布尔值:
PushBool
, ShiftBool
- 字符串:
PushString
, ShiftString
- 字节切片:
PushBytes
, ShiftBytes
高级用法
1. 处理结构体
type Person struct {
ID uint32
Name string
Age uint8
Height float32
}
func PackPerson(p *Person) ([]byte, error) {
buffer := new(bytes.Buffer)
packer := binpacker.NewPacker(buffer)
err := packer.PushUint32(p.ID)
err = packer.PushString(p.Name)
err = packer.PushUint8(p.Age)
err = packer.PushFloat32(p.Height)
if err != nil {
return nil, err
}
return buffer.Bytes(), nil
}
func UnpackPerson(data []byte) (*Person, error) {
buffer := bytes.NewBuffer(data)
unpacker := binpacker.NewUnpacker(buffer)
var p Person
err := unpacker.ShiftUint32(&p.ID)
err = unpacker.ShiftString(&p.Name)
err = unpacker.ShiftUint8(&p.Age)
err = unpacker.ShiftFloat32(&p.Height)
if err != nil {
return nil, err
}
return &p, nil
}
2. 处理变长数据
// 打包变长数据切片
func PackSlice(items []string) ([]byte, error) {
buffer := new(bytes.Buffer)
packer := binpacker.NewPacker(buffer)
// 先写入长度
err := packer.PushUint32(uint32(len(items)))
if err != nil {
return nil, err
}
// 再逐个写入元素
for _, item := range items {
err = packer.PushString(item)
if err != nil {
return nil, err
}
}
return buffer.Bytes(), nil
}
// 解包变长数据切片
func UnpackSlice(data []byte) ([]string, error) {
buffer := bytes.NewBuffer(data)
unpacker := binpacker.NewUnpacker(buffer)
var length uint32
err := unpacker.ShiftUint32(&length)
if err != nil {
return nil, err
}
items := make([]string, length)
for i := 0; i < int(length); i++ {
err = unpacker.ShiftString(&items[i])
if err != nil {
return nil, err
}
}
return items, nil
}
注意事项
- 字节序:binpacker默认使用大端序(BigEndian),如果需要小端序,需要自行处理
- 错误处理:每次打包/解包操作都可能返回错误,应该检查这些错误
- 数据对齐:确保打包和解包的顺序完全一致
- 性能考虑:对于高性能场景,可以考虑预分配足够大的buffer
binpacker是一个简单易用的二进制数据序列化库,适合协议编解码、文件格式处理等场景。对于更复杂的需求,也可以考虑protobuf、msgpack等更专业的序列化方案。