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 进行转换。