Bytes模块
Bytes模块介绍
参考文档: https://jin-yang.github.io/post/golang-common-module-bytes-introduce.html
Golang 中的 bytes 包使用频率较高,主要提供了字节相关的操作,通常作为缓冲区使用。
简介
String VS. Bytes
String 是固定的一系列字节,创建之后不能被修改;而 Bytes 可以动态调整。所以,如果要修改字符串的内容,需要转换为 Bytes 。
两者之间可以相互转换,例如:
s := "abc"
b := []byte(s)
s := string(b)
在两者相互转换时,会先完成内存申请,然后将对应的内容进行拷贝。
bytes.Buffer
将一块内存提供Reader接口操作。
bytes.Buffer
是一个字节类型的缓冲器,可变长,实际上内部指向的是一个 Slice 对象。
如下是一些常见的操作:
//----- 分配对象可以动态扩容,如果大小是固定可以指定打消
var b bytes.Buffer
b := new(bytes.Buffer)
b := bytes.NewBufferString("hello")
b := bytes.NewBuffer([]byte("hello"))
b.Write([]byte("Hello"))
b.WriteString("Hello")
b.Bytes() // 获取对应的Slice
在该包中,提供了一个如下的结构体。
type Buffer struct {
buf []byte // contents are the bytes buf[off : len(buf)]
off int // read at &buf[off], write at &buf[len(buf)]
// memory to hold first slice; helps small buffers avoid allocation.
bootstrap [64]byte
// last read operation, so that Unread* can work correctly.
lastRead readOp
}
数据会保存在 buf []byte
对象中,那么无非就是当内存空间不足的时候如何进行扩容。
序列化
二进制文件读写方式,可以通过标准库提供的 encoding/binary
库。
package main
import (
"bytes"
"encoding/binary"
"log"
"os"
"unsafe"
)
const (
T_WRITE = 0x1234
)
type Package struct {
Magic [4]byte
Type uint16
Length uint32
}
func main() {
file, err := os.OpenFile("foobar.bin", os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0644)
if err != nil {
log.Fatal(err)
}
defer file.Close()
// Write
data := &Package{
Magic: [4]byte{'A', 'B', 'C', 'D'},
Type: T_WRITE,
Length: 10,
}
buff := new(bytes.Buffer)
binary.Write(buff, binary.LittleEndian, data)
nwritten, err := file.Write(buff.Bytes())
if err != nil {
log.Fatal(err)
}
log.Printf("Write %d bytes\n", nwritten)
// Read
if _, err := file.Seek(0, 0); err != nil {
log.Fatal(err)
}
rdata := make([]byte, unsafe.Sizeof(Package{}))
pkg := Package{}
nread, err := file.Read(rdata)
if err != nil {
log.Fatal(err)
}
log.Printf("Read %d bytes\n", nread)
binary.Read(bytes.NewBuffer(rdata), binary.LittleEndian, &pkg)
log.Printf("Got data %v\n", pkg)
}
如果是多个二进制文件,那么就可以通过 binary.LittleEndian.Uint16
进行转换。