Go中binary.Write必须显式指定字节序(LittleEndian或BigEndian),否则panic;结构体需导出字段且用定长类型;变长字段须分步处理长度与内容;网络读取需确保io.ReadFull完整读取。
Go 的 encoding/binary 不提供默认字节序,binary.Write 第二个参数必须传入 binary.LittleEndian 或 binary.BigEndian。漏传会 panic:panic: binary.Write: invalid type interface {}(实际是因未传入 binary.ByteOrder 导致内部反射失败)。
常见写法:
data := uint32(0x12345678) err := binary.Write(w, binary.LittleEndian, data)
注意:w 必须是实现了 io.Writer 的类型(如 *os.File、bytes.Buffer)。结构体写入也同理,字段必须导出且按顺序连续编码。
用 binary.Read 读结构体时,Go 会按字段声明顺序逐个解码,但不会跳过填充字节。若结构体含 int、uintptr 等平台相关类型,或字段间有未导出字段,读写结果必然错乱。
安全做法是只使用定长基础类型,并显式对齐:
uint32 代替 int,用 [32]byte 代替 string
// +build ignore 注释无用,真正有效的是 unsafe.Sizeof 校验binary.Read 返回 io.ErrUnexpectedEOF
binary.Read 和 binary.Write 对 []byte、string 只写入长度(作为 uint64),不写内容;对 slice 类型甚至直接报错:binary.Read: invalid type 。
正确方式是分步处理:
str := "hello" // 先写长度 binary.Write(w, binary.LittleEndian, uint64(len(str))) // 再写字节流 w.Write([]byte(str))
读取时反向操作:先读 uint64 得长度 n,再用 io.ReadFull(r, make([]byte, n)) 读内容。忽略长度校验会导致越界或阻塞。
当 r 是 net.Conn 或其他非阻塞 reader 时,binary.Read(r, order, &v) 可能只读到部分字节就返回 nil 错误(实际是成功读了几个字节),导致后续解析错位。
根本原因是 binary.Read 底层调用 io.ReadFull,而 io.ReadFull 要求「必须读满」,否则返回 io.ErrUnexpectedEOF 或 io.EOF。但网络连接可能暂时没发完,需重试:
r 为 bufio.Reader 并设置足够大缓存io.ReadFull 直到成功,不依赖 binary.Read 自动重试io.ReadFull(r, buf) 先读原始字节,再用 binary.Read(bytes.NewReader(buf), ...) 解析字节序、结构体对齐、变长字段边界、IO 完整性——这四点漏掉任一个,二进制读写就会静默出错,且很难通过日志定位。