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 就像一個集裝箱容器,能夠存東西,取東西(存取數據)bash
建立緩衝器ui
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())
}
複製代碼
輸出spa
hello,hello,hello
[104 101 108 108 111],[104 101 108 108 111],[104 101 108 108 111]
[] []
複製代碼
寫入到緩衝器
buffer在new的時候是空的,也是能夠直接Write的code
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]
複製代碼
WriteStringstring
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())
}
複製代碼
結果it
hello,[104 101 108 108 111]
hello world,[104 101 108 108 111 32 119 111 114 108 100]
複製代碼
WriteByteio
func (b *Buffer) WriteByte(c byte) error
複製代碼
func main() {
var s byte = '?'
buf := bytes.NewBufferString("hello")
fmt.Println(buf.Bytes())
buf.WriteByte(s)
fmt.Println(buf.Bytes())
}
複製代碼
WriteRuneast
func (b *Buffer) WriteRune(r Rune) (n int,err error)
複製代碼
func main(){
var s rune = '好'
buf := bytes.NewBufferString("hello")
fmt.Println(buf.String())
buf.WriteRune(s)
fmt.Println(buf.String())
}
複製代碼
結果
22909
[104 101 108 108 111]
[104 101 108 108 111 229 165 189]
複製代碼
從緩衝器中寫出
func main() {
file,_ := os.Create("test.txt")
buf := bytes.NewBufferString("hello world")
buf.WriteTo(file)
}
複製代碼
讀出緩衝器
Read
func (b *Buffer) Read(p []byte)(n int,err error)
複製代碼
func main() {
s1 := []byte("hello")
buff :=bytes.NewBuffer(s1)
s2 := []byte(" world")
buff.Write(s2)
fmt.Println(buff.String())
s3 := make([]byte,3)
buff.Read(s3)
fmt.Println(string(s3))
fmt.Println(buff.String())
buff.Read(s3)
fmt.Println(string(s3))
fmt.Println(buff.String())
}
複製代碼
ReadByte
返回緩衝器頭部的第一個byte
func (b *Buffer) ReadByte() (c byte,err error)
複製代碼
func main() {
buf := bytes.NewBufferString("hello")
fmt.Println(buf.String()) // hello
b,_:= buf.ReadByte()
fmt.Println(string(b)) //h
fmt.Println(buf.String()) //ello
}
複製代碼
ReadRun
ReadRune方法,返回緩衝器頭部的第一個rune
func (b *Buffer) ReadRune() (r rune,size int,err error)
複製代碼
func main() {
buf1 := bytes.NewBufferString("你好xuxiaofeng")
fmt.Println(buf1.Bytes())
b1,n1,_ := buf1.ReadRune()
fmt.Println(string(b1))
fmt.Println(n1)
buf := bytes.NewBufferString("hello")
fmt.Println(buf.String())
b,n,_:= buf.ReadRune()
fmt.Println(n)
fmt.Println(string(b))
fmt.Println(buf.String())
}
複製代碼
爲何n==3,而n1==1呢?咱們看下ReadRune 的源碼
func (b *Buffer) ReadRune() (r rune, size int, err error) {
if b.empty() {
b.Reset()
return 0, 0, io.EOF
}
c := b.buf[b.off]
if c < utf8.RuneSelf {
b.off++
b.lastRead = opReadRune1
return rune(c), 1, nil
}
r, n := utf8.DecodeRune(b.buf[b.off:])
b.off += n
b.lastRead = readOp(n)
return r, n, nil
}
複製代碼
ReadBytes
ReadBytes方法,須要一個byte做爲分隔符,讀的時候從緩衝器裏找出第一個出現的分隔符,緩衝器頭部開始到分隔符之間的byte返回。
func (b *Buffer) ReadBytes(delim byte) (line []byte,err error)
複製代碼
func main() {
var d byte = 'f'
buf := bytes.NewBufferString("xuxiaofeng")
fmt.Println(buf.String())
b,_ :=buf.ReadBytes(d)
fmt.Println(string(b))
fmt.Println(buf.String())
}
複製代碼
至關於有一個分隔符
ReadString
和readBytes方法相似
讀入緩衝器
ReadFrom方法,從一個實現io.Reader接口的r,把r的內容讀到緩衝器裏,n返回讀的數量
func (b *Buffer) ReadFrom(r io.Reader) (n int64,err error)
複製代碼
func main(){
file, _ := os.Open("text.txt")
buf := bytes.NewBufferString("bob ")
buf.ReadFrom(file)
fmt.Println(buf.String())
}
複製代碼
從緩衝器取出
Next方法,返回前n個byte(slice),原緩衝器變
func (b *Buffer) Next(n int) []byte
複製代碼
func main() {
buf := bytes.NewBufferString("helloworld")
fmt.Println(buf.String()) // helloworld
b := buf.Next(2)
fmt.Println(string(b)) // he
}
複製代碼
緩衝區原理介紹
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
}
複製代碼