分享
  1. 首页
  2. 文章

golang bytes.buffer详解

豆瓣奶茶 · · 2047 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

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]

WriteByte

func (b *Buffer) WriteByte(c byte) error

func main() {
 var s byte = '?'
 buf := bytes.NewBufferString("hello")
 fmt.Println(buf.Bytes()) // [104 101 108 108 111]
 buf.WriteByte(s)
 fmt.Println(buf.Bytes()) // [104 101 108 108 111 63]
}

WriteRune

func (b *Buffer) WriteRune(r Rune) (n int,err error)

func main(){
 var s rune = '好'
 buf := bytes.NewBufferString("hello")
 fmt.Println(buf.String()) //hello
 buf.WriteRune(s) 
 fmt.Println(buf.String()) //hello好
}

结果

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()) //hello world
 s3 := make([]byte,3)
 buff.Read(s3)
 fmt.Println(string(s3)) //hel,s3的容量为3,只能读3个
 fmt.Println(buff.String()) //lo world
 buff.Read(s3) // 会把s3覆盖掉
 fmt.Println(string(s3)) // lo 
 fmt.Println(buff.String()) // world
}

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()) //[228 189 160 229 165 189 120 117 120 105 97 111 102 101 110 103]
 b1,n1,_ := buf1.ReadRune()
 fmt.Println(string(b1)) // 你
 fmt.Println(n1)
 
 
 buf := bytes.NewBufferString("hello")
 fmt.Println(buf.String()) //hello
 b,n,_:= buf.ReadRune()
 fmt.Println(n) // 1
 fmt.Println(string(b)) //h
 fmt.Println(buf.String()) //ello
}

为什么n==3,而n1==1呢?我们看下ReadRune 的源码

func (b *Buffer) ReadRune() (r rune, size int, err error) {
 if b.empty() {
 // Buffer is empty, reset to recover space.
 b.Reset()
 return 0, 0, io.EOF
 }
 c := b.buf[b.off]
 if c < utf8.RuneSelf { // 就是在这里判断,读取的第一个字符是不是Rune
 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()) //bob hello world
}

从缓冲器取出

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
}

有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:豆瓣奶茶

查看原文:golang bytes.buffer详解

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
2047 次点击
1 回复 | 直到 2025年05月13日 22:27:37
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏