Golang bytes.buffer详解
原文:https://www.jianshu.com/p/e53083132a25
Buffer 介绍
Buffer 是 bytes 包中的一个 type Buffer struct{…}
A buffer is a variable-sized buffer of bytes with Read and Write methods. The zero value for Buffer is an empty buffer ready to use.
(是一个变长的 buffer,具有 Read 和Write 方法。 Buffer 的 零值 是一个 空的 buffer,但是可以使用)
Buffer 就像一个集装箱容器,可以存东西,取东西(存取数据)
创建缓冲器
func main() { buf1 := bytes.NewBufferString("hello") buf2 := bytes.NewBuffer([]byte("hello")) buf3 := bytes.NewBuffer([]byte{'h','e','l','l','o'}) fmt.Printf("%v,%v,%v\n",buf1,buf2,buf3) fmt.Printf("%v,%v,%v\n",buf1.Bytes(),buf2.Bytes(),buf3.Bytes()) buf4 := bytes.NewBufferString("") buf5 := bytes.NewBuffer([]byte{}) fmt.Println(buf4.Bytes(),buf5.Bytes()) }
输出
hello,hello,hello [104 101 108 108 111],[104 101 108 108 111],[104 101 108 108 111] [] []
写入到缓冲器
buffer在new的时候是空的,也是可以直接Write的
Write
func (b *Buffer) Write(p []byte) (n int,err error)
func main() { s := []byte(" world") buf := bytes.NewBufferString("hello") fmt.Printf("%v,%v\n",buf.String(),buf.Bytes()) buf.Write(s) fmt.Printf("%v,%v\n",buf.String(),buf.Bytes()) }
结果
hello,[104 101 108 108 111] hello world,[104 101 108 108 111 32 119 111 114 108 100]
WriteString
func (b *Buffer) WriteString(s string)(n int,err error)
func main() { s := " world" buf := bytes.NewBufferString("hello") fmt.Printf("%v,%v\n",buf.String(),buf.Bytes()) buf.WriteString(s) fmt.Printf("%v,%v\n",buf.String(),buf.Bytes()) }
结果
hello,[104 101 108 108 111] hello world,[104 101 108 108 111 32 119 111 114 108 100]
缓冲区原理介绍
go字节缓冲区底层以字节切片做存储,切片存在长度len与容量cap, 缓冲区写从长度len的位置开始写,当len>cap时,会自动扩容。缓冲区读会从内置标记off位置开始读(off始终记录读的起始位置),当off==len时,表明缓冲区已全部读完
并重置缓冲区(len=off=0),此外当将要内容长度+已写的长度(即len) <= cap/2时,缓冲区前移覆盖掉已读的内容(off=0,len-=off),从避免缓冲区不断扩容
go字节缓冲区底层以字节切片做存储,切片存在长度len与容量cap, 缓冲区写从长度len的位置开始写,当len>cap时,会自动扩容。缓冲区读会从内置标记off位置开始读(off始终记录读的起始位置),当off==len时,表明缓冲区已全部读完
并重置缓冲区(len=off=0),此外当将要内容长度+已写的长度(即len) <= cap/2时,缓冲区前移覆盖掉已读的内容(off=0,len-=off),从避免缓冲区不断扩容
func main() { byteSlice := make([]byte, 20) byteSlice[0] = 1 // 将缓冲区第一个字节置1 byteBuffer := bytes.NewBuffer(byteSlice) // 创建20字节缓冲区 len = 20 off = 0 c, _ := byteBuffer.ReadByte() // off+=1 fmt.Printf("len:%d, c=%d\n", byteBuffer.Len(), c) // len = 20 off =1 打印c=1 byteBuffer.Reset() // len = 0 off = 0 fmt.Printf("len:%d\n", byteBuffer.Len()) // 打印len=0 byteBuffer.Write([]byte("hello byte buffer")) // 写缓冲区 len+=17 fmt.Printf("len:%d\n", byteBuffer.Len()) // 打印len=17 byteBuffer.Next(4) // 跳过4个字节 off+=4 c, _ = byteBuffer.ReadByte() // 读第5个字节 off+=1 fmt.Printf("第5个字节:%d\n", c) // 打印:111(对应字母o) len=17 off=5 byteBuffer.Truncate(3) // 将未字节数置为3 len=off+3=8 off=5 fmt.Printf("len:%d\n", byteBuffer.Len()) // 打印len=3为未读字节数 上面len=8是底层切片长度 byteBuffer.WriteByte(96) // len+=1=9 将y改成A byteBuffer.Next(3) // len=9 off+=3=8 c, _ = byteBuffer.ReadByte() // off+=1=9 c=96 fmt.Printf("第9个字节:%d\n", c) // 打印:96 }
demo1
package main import "bytes" import "log" func main(){ buf := &bytes.Buffer{} buf.WriteString("abcdefg") str, _ := buf.ReadString('?') log.Println("str = ", str) log.Println("buff = ", buf.String()) }
输出:
[root@localhost]# go run buffer.go 2020/06/05 19:12:42 str = abcdefg 2020/06/05 19:12:42 buff =
demo2
// MyBuffer2 project main.go package main import ( "bytes" "log" "os" ) func main() { log.SetFlags(log.Lshortfile) buff := bytes.NewBufferString("123456789") log.Println("buff = ", buff.String()) s := make([]byte, 4) n, _ := buff.Read(s) log.Println("buff = ", buff.String()) log.Println("s = ", string(s)) log.Println("n = ", n) n, _ = buff.Read(s) log.Println("buff = ", buff.String()) log.Println("s = ", string(s)) log.Println("n = ", n) n, _ = buff.Read(s) log.Println("buff = ", buff.String()) log.Println("s = ", string(s)) log.Println("n = ", n) buff.Reset() buff.WriteString("abcdefg") log.Println("buff = ", buff.String()) b, _ := buff.ReadByte() log.Println("b = ", string(b)) log.Println("buff = ", buff.String()) b, _ = buff.ReadByte() log.Println("b = ", string(b)) log.Println("buff = ", buff.String()) bs, _ := buff.ReadBytes('e') log.Println("bs = ", string(bs)) log.Println("buff = ", buff.String()) buff.Reset() buff.WriteString("编译输出GO") r, l, _ := buff.ReadRune() log.Println("r = ", r, ", l = ", l, ", string(r) = ", string(r)) buff.Reset() buff.WriteString("qwer") str, _ := buff.ReadString('?') log.Println("str = ", str) log.Println("buff = ", buff.String()) buff.WriteString("qwer") str, _ = buff.ReadString('w') log.Println("str = ", str) log.Println("buff = ", buff.String()) file, _ := os.Open("doc.go") buff.Reset() buff.ReadFrom(file) log.Println("doc.go = ", buff.String()) buff.Reset() buff.WriteString("中国人") cbyte := buff.Bytes() log.Println("cbyte = ", cbyte) }
输出:
C:/Go/bin/go.exe build -i [D:/golang/src/MyBuffer2] 成功: 进程退出代码 0. D:/golang/src/MyBuffer2/MyBuffer2.exe [D:/golang/src/MyBuffer2] main.go:13: buff = 123456789 main.go:17: buff = 56789 main.go:18: s = 1234 main.go:19: n = 4 main.go:22: buff = 9 main.go:23: s = 5678 main.go:24: n = 4 main.go:27: buff = main.go:28: s = 9678 main.go:29: n = 1 main.go:33: buff = abcdefg main.go:36: b = a main.go:37: buff = bcdefg main.go:40: b = b main.go:41: buff = cdefg main.go:44: bs = cde main.go:45: buff = fg main.go:50: r = 32534 , l = 3 , string(r) = 编 main.go:55: str = qwer main.go:56: buff = main.go:60: str = qw main.go:61: buff = er main.go:66: doc.go = // MyBuffer2 project doc.go /* MyBuffer2 document */ package main main.go:71: cbyte = [228 184 173 229 155 189 228 186 186] 成功: 进程退出代码 0.