Golang standard library: bytes package – byte slice byte array convenient operation

2.2 bytes – byte slice convenient operation

This package defines some convenience operations for manipulating byte slices. Because strings can be represented as []byte, the functions and methods defined by the bytes package are very similar to the strings package, so the explanation will be similar to the strings package and can even be referred to directly.

Note: For convenience, []byte will be called byte array

Buffer type

2.2.1 Whether a sub-slice exists

// subslice subslice in b, returns true
func Contains(b, subslice []byte) bool

The bytes.Index function is called internally in this function (will be explained later):

 func Contains(b, subslice []byte) bool {<!-- -->
    return Index(b, subslice) != -1
    }

Off-topic: Comparing strings.Contains, you will find that one judgment is >=0, and the other judgment is != -1. It can be seen that the library is not a person. Written without consistency.

2.2.2 []byte occurrence count

//The number of times slice sep appears in s (no overlap)
func Count(s, sep []byte) int

Different from the strings implementation, the core code of Count in this package is as follows:

count := 0
c := sep[0]
i := 0
t := s[:len(s)-n + 1]
for i < len(t) {<!-- -->
// Determine whether the first byte of sep is in t[i:]
// If it is, compare the corresponding bytes
if t[i] != c {<!-- -->
o := IndexByte(t[i:], c)
if o < 0 {<!-- -->
break
}
i + = o
}
// Execution here means sep[0] == t[i]
if n == 1 || Equal(s[i:i + n], sep) {<!-- -->
count++
i + = n
continue
}
i++
}

2.2.3 Runes type conversion

//Convert []byte to []rune
func Runes(s []byte) []rune

This function converts []byte to []rune, suitable for multi-byte characters such as Chinese characters, example:

b:=[]byte("Hello, world")
for k,v:=range b{<!-- -->
fmt.Printf("%d:%s |",k,string(v))
}
r:=bytes.Runes(b)
for k,v:=range r{<!-- -->
fmt.Printf("%d:%s|",k,string(v))
}

operation result:

0:? |1:? |2: |3:? |4:¥ |5:? |6:? |7:? |8: |9:? |10:? |11: |12: ? |13: |14: |
0:you|1:good|2:,|3:world|4:world|

2.2.4 Reader Type

type Reader struct {<!-- -->
s[]byte
i int64 // current reading index
prevRune int // The subscript of the previous character, it may also be < 0
}

The Reader type under the bytes package implements multiple interfaces such as Reader, ReaderAt, RuneReader, RuneScanner, ByteReader, ByteScanner, ReadSeeker, Seeker, WriterTo and so on under the io package. Mainly used for Read data.

We need to initialize the bytes.Reader type object through the bytes.NewReader method. Pass in []byte type data during initialization. The NewReader function signature is as follows:

func NewReader(b []byte) *Reader

If the object is declared directly, the data can be rewritten through the Reset method, example:

x:=[]byte("Hello, world")

r1:=bytes.NewReader(x)
d1:=make([]byte,len(x))
n,_:=r1.Read(d1)
fmt.Println(n,string(d1))

r2:=bytes.Reader{<!-- -->}
r2.Reset(x)
d2:=make([]byte,len(x))
n,_=r2.Read(d2)
fmt.Println(n,string(d2))

Output result:

15 Hello world
15 hello world

Reader contains 8 reading-related methods and implements the 9 interfaces under the io package mentioned earlier (the ReadSeeker interface embeds the Reader and Seeker interfaces):

//Read data to b
func (r *Reader) Read(b []byte) (n int, err error)
//Read a byte
func (r *Reader) ReadByte() (byte, error)
// read a character
func (r *Reader) ReadRune() (ch rune, size int, err error)
//Read data to w
func (r *Reader) WriteTo(w io.Writer) (n int64, err error)
//The progress subscript points to the previous byte, if r.i <= 0, an error is returned.
func (r *Reader) UnreadByte()
// The progress subscript points to the previous character. If r.i <= 0, an error is returned and can only be used once after each ReadRune method, otherwise an error is returned.
func (r *Reader) UnreadRune()
// Read the data of r.s[off:] to b. This method ignores the progress subscript i and does not use or modify it.
func (r *Reader) ReadAt(b []byte, off int64) (n int, err error)
// According to the value of whence, modify and return the progress subscript i. When whence == 0, the progress subscript is modified to off. When whence == 1, the progress subscript is modified to i + off. When whence == 2, the progress subscript is modified. The subscript is modified to len[s] + off.
// off can be a negative number, and whence can only be 0, 1, 2. When whence is other values or the calculated progress subscript is out of bounds, an error will be returned.
func (r *Reader) Seek(offset int64, whence int) (int64, error)

Example:

x := []byte("Hello, world")
r1 := bytes.NewReader(x)

ch, size, _ := r1.ReadRune()
fmt.Println(size, string(ch))
_ = r1.UnreadRune()
ch, size, _ = r1.ReadRune()
fmt.Println(size, string(ch))
_ = r1.UnreadRune()

by, _ := r1.ReadByte()
fmt.Println(by)
_ = r1.UnreadByte()
by, _ = r1.ReadByte()
fmt.Println(by)
_ = r1.UnreadByte()

d1 := make([]byte, 6)
n, _ := r1.Read(d1)
fmt.Println(n, string(d1))

d2 := make([]byte, 6)
n, _ = r1.ReadAt(d2, 0)
fmt.Println(n, string(d2))

w1 := & amp;bytes.Buffer{<!-- -->}
_, _ = r1.Seek(0, 0)
_, _ = r1.WriteTo(w1)
fmt.Println(w1.String())

operation result:

3 you
3 you
228
228
6 hello
6 hello
Hello World

2.2.5 Buffer type

type Buffer struct {<!-- -->
buf[]byte
off int
lastRead readOp
}

At the end of the previous example, we used the bytes.Buffer type, which implements the ByteScanner, ByteWriter, ReadWriter, Reader, ReaderFrom, RuneReader, RuneScanner, StringWriter, Writer, WriterTo and other interfaces under the io package, making it easy to read write operation.

The data that the object can read is buf[off : len(buf)], off represents the progress subscript, and lastRead represents the number of bytes occupied by the last character read, which facilitates Unread* related operations.

Buffer objects can be initialized through 3 methods:

a := bytes.NewBufferString("Hello World")
b := bytes.NewBuffer([]byte("Hello World"))
c := bytes.Buffer{<!-- -->}

fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
}

Output result:

Hello World
Hello World
{<!-- -->[] 0 0}

Buffer contains 21 methods related to reading and writing. The usage of most of the methods with the same name is similar to that mentioned above. Here we only demonstrate 3 of them:

//After reading the byte delim, return this byte and the previously read bytes in the form of a byte array. If no matching byte is found after traversing b.buf, an error (usually EOF) is returned.
func (b *Buffer) ReadBytes(delim byte) (line []byte, err error)
// After reading the byte delim, return the byte and the previously read byte in the form of a string. If no matching byte is found after traversing b.buf, an error (usually EOF) is returned.
func (b *Buffer) ReadString(delim byte) (line string, err error)
//Truncate b.buf and discard the data after b.off + n. When n == 0, call the Reset method to reset the object. When n goes out of bounds (n < 0 || n > b.Len()), the method will trigger a panic.
func (b *Buffer) Truncate(n int)

Example:

a := bytes.NewBufferString("Good Night")

x, err := a.ReadBytes('t')
if err != nil {<!-- -->
    fmt.Println("delim:t err:", err)
} else {<!-- -->
    fmt.Println(string(x))
}

a.Truncate(0)
a.WriteString("Good Night")
fmt.Println(a.Len())
a.Truncate(5)
fmt.Println(a.Len())
y, err := a.ReadString('N')
if err != nil {<!-- -->
    fmt.Println("delim:N err:", err)
} else {<!-- -->
    fmt.Println(y)
}

Output result:

Good Night
10
5
delim:N err: EOF

2.2.6 Other functions

Most of the other functions and methods are similar to those under the strings package, except that the data source is changed from string to []byte. Please refer to the usage of the strings package.