该包定义了一些操作 byte slice 的便利操作。因为字符串可以表示为 []byte,因此,bytes 包定义的函数、方法等和 strings 包很类似,所以讲解时会和 strings 包类似甚至可以直接参考。
说明:为了方便,会称呼 []byte 为 字节数组
// 子 slice subslice 在 b 中,返回 true func Contains(b, subslice []byte) bool
该函数的内部调用了 bytes.Index 函数(在后面会讲解):
func Contains(b, subslice []byte) bool { return Index(b, subslice) != -1 }
题外:对比 strings.Contains 你会发现,一个判断 >=0,一个判断 != -1,可见库不是一个人写的,没有做到一致性。
strings.Contains
>=0
!= -1
// slice sep 在 s 中出现的次数(无重叠) func Count(s, sep []byte) int
和 strings 实现不同,此包中的 Count 核心代码如下:
count := 0 c := sep[0] i := 0 t := s[:len(s)-n+1] for i < len(t) { // 判断 sep 第一个字节是否在 t[i:] 中 // 如果在,则比较之后相应的字节 if t[i] != c { o := IndexByte(t[i:], c) if o < 0 { break } i += o } // 执行到这里表示 sep[0] == t[i] if n == 1 || Equal(s[i:i+n], sep) { count++ i += n continue } i++ }
// 将 []byte 转换为 []rune func Runes(s []byte) []rune
该函数将 []byte 转换为 []rune ,适用于汉字等多字节字符,示例:
b:=[]byte("你好,世界") 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)) }
运行结果:
0:ä |1:½ |2: |3:å |4:¥ |5:½ |6:ï |7:¼ |8: |9:ä |10:¸ |11: |12:ç |13: |14: | 0:你|1:好|2:,|3:世|4:界|
type Reader struct { s []byte i int64 // 当前读取下标 prevRune int // 前一个字符的下标,也可能 < 0 }
bytes 包下的 Reader 类型实现了 io 包下的 Reader, ReaderAt, RuneReader, RuneScanner, ByteReader, ByteScanner, ReadSeeker, Seeker, WriterTo 等多个接口。主要用于 Read 数据。
我们需要在通过 bytes.NewReader 方法来初始化 bytes.Reader 类型的对象。初始化时传入 []byte 类型的数据。NewReader 函数签名如下:
func NewReader(b []byte) *Reader
如果直接声明该对象了,可以通过 Reset 方法重新写入数据,示例:
x:=[]byte("你好,世界") 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))
输出结果:
15 你好,世界 15 你好,世界
Reader 包含了 8 个读取相关的方法,实现了前面提到的 io 包下的 9 个接口(ReadSeeker 接口内嵌 Reader 和 Seeker 两个接口):
// 读取数据至 b func (r *Reader) Read(b []byte) (n int, err error) // 读取一个字节 func (r *Reader) ReadByte() (byte, error) // 读取一个字符 func (r *Reader) ReadRune() (ch rune, size int, err error) // 读取数据至 w func (r *Reader) WriteTo(w io.Writer) (n int64, err error) // 进度下标指向前一个字节,如果 r.i <= 0 返回错误。 func (r *Reader) UnreadByte() // 进度下标指向前一个字符,如果 r.i <= 0 返回错误,且只能在每次 ReadRune 方法后使用一次,否则返回错误。 func (r *Reader) UnreadRune() // 读取 r.s[off:] 的数据至b,该方法忽略进度下标 i,不使用也不修改。 func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) // 根据 whence 的值,修改并返回进度下标 i ,当 whence == 0 ,进度下标修改为 off,当 whence == 1 ,进度下标修改为 i+off,当 whence == 2 ,进度下标修改为 len[s]+off. // off 可以为负数,whence 的只能为 0,1,2,当 whence 为其他值或计算后的进度下标越界,则返回错误。 func (r *Reader) Seek(offset int64, whence int) (int64, error)
示例:
x := []byte("你好,世界") 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 := &bytes.Buffer{} _, _ = r1.Seek(0, 0) _, _ = r1.WriteTo(w1) fmt.Println(w1.String())
3 你 3 你 228 228 6 你好 6 你好 你好,世界
type Buffer struct { buf []byte off int lastRead readOp }
在上一个示例的最后,我们使用了 bytes.Buffer 类型,该类型实现了 io 包下的 ByteScanner, ByteWriter, ReadWriter, Reader, ReaderFrom, RuneReader, RuneScanner, StringWriter, Writer, WriterTo 等接口,可以方便的进行读写操作。
对象可读取数据为 buf[off : len(buf)], off 表示进度下标,lastRead 表示最后读取的一个字符所占字节数,方便 Unread* 相关操作。
Buffer 可以通过 3 中方法初始化对象:
a := bytes.NewBufferString("Hello World") b := bytes.NewBuffer([]byte("Hello World")) c := bytes.Buffer{} fmt.Println(a) fmt.Println(b) fmt.Println(c) }
Hello World Hello World {[] 0 0}
Buffer 包含了 21 个读写相关的方法,大部分同名方法的用法与前面讲的类似,这里只讲演示其中的 3 个方法:
// 读取到字节 delim 后,以字节数组的形式返回该字节及前面读取到的字节。如果遍历 b.buf 也找不到匹配的字节,则返回错误(一般是 EOF) func (b *Buffer) ReadBytes(delim byte) (line []byte, err error) // 读取到字节 delim 后,以字符串的形式返回该字节及前面读取到的字节。如果遍历 b.buf 也找不到匹配的字节,则返回错误(一般是 EOF) func (b *Buffer) ReadString(delim byte) (line string, err error) // 截断 b.buf , 舍弃 b.off+n 之后的数据。n == 0 时,调用 Reset 方法重置该对象,当 n 越界时(n < 0 || n > b.Len() )方法会触发 panic. func (b *Buffer) Truncate(n int)
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) }
Good Night 10 5 delim:N err: EOF
其它大部分函数、方法与 strings 包下的函数、方法类似,只是数据源从 string 变为了 []byte ,请参考 strings 包的用法。
Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8