go语言string之Buffer与Builder
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了go语言string之Buffer与Builder相关的知识,希望对你有一定的参考价值。
参考技术A 操作字符串离不开字符串的拼接,但是Go中string是只读类型,大量字符串的拼接会造成性能问题。拼接字符串,无外乎四种方式,采用“+”,“fmt.Sprintf()”,"bytes.Buffer","strings.Builder"
上面我们创建10万字符串拼接的测试,可以发现"bytes.Buffer","strings.Builder"的性能最好,约是“+”的1000倍级别。
这是由于string是不可修改的,所以在使用“+”进行拼接字符串,每次都会产生申请空间,拼接,复制等操作,数据量大的情况下非常消耗资源和性能。而采用Buffer等方式,都是预先计算拼接字符串数组的总长度(如果可以知道长度),申请空间,底层是slice数组,可以以append的形式向后进行追加。最后在转换为字符串。这申请了不断申请空间的操作,也减少了空间的使用和拷贝的次数,自然性能也高不少。
bytes.buffer是一个缓冲byte类型的缓冲器存放着都是byte
是一个变长的 buffer,具有 Read 和Write 方法。 Buffer 的 零值 是一个 空的 buffer,但是可以使用,底层就是一个 []byte, 字节切片。
向Buffer中写数据,可以看出Buffer中有个Grow函数用于对切片进行扩容。
从Buffer中读取数据
strings.Builder的方法和bytes.Buffer的方法的命名几乎一致。
但实现并不一致,Builder的Write方法直接将字符拼接slice数组后。
其没有提供read方法,但提供了strings.Reader方式
Reader 结构:
Buffer:
Builder:
可以看出Buffer和Builder底层都是采用[]byte数组进行装载数据。
先来说说Buffer:
创建好Buffer是一个empty的,off 用于指向读写的尾部。
在写的时候,先判断当前写入字符串长度是否大于Buffer的容量,如果大于就调用grow进行扩容,扩容申请的长度为当前写入字符串的长度。如果当前写入字符串长度小于最小字节长度64,直接创建64长度的[]byte数组。如果申请的长度小于二分之一总容量减去当前字符总长度,说明存在很大一部分被使用但已读,可以将未读的数据滑动到数组头。如果容量不足,扩展2*c + n 。
其String()方法就是将字节数组强转为string
Builder是如何实现的。
Builder采用append的方式向字节数组后添加字符串。
从上面可以看出,[]byte的内存大小也是以倍数进行申请的,初始大小为 0,第一次为大于当前申请的最大 2 的指数,不够进行翻倍.
可以看出如果旧容量小于1024进行翻倍,否则扩展四分之一。(2048 byte 后,申请策略的调整)。
其次String()方法与Buffer的string方法也有明显区别。Buffer的string是一种强转,我们知道在强转的时候是需要进行申请空间,并拷贝的。而Builder只是指针的转换。
这里我们解析一下 *(*string)(unsafe.Pointer(&b.buf)) 这个语句的意思。
先来了解下unsafe.Pointer 的用法。
也就是说,unsafe.Pointer 可以转换为任意类型,那么意味着,通过unsafe.Pointer媒介,程序绕过类型系统,进行地址转换而不是拷贝。
即*A => Pointer => *B
就像上面例子一样,将字节数组转为unsafe.Pointer类型,再转为string类型,s和b中内容一样,修改b,s也变了,说明b和s是同一个地址。但是对s重新赋值后,意味着s的地址指向了“WORLD”,它们所使用的内存空间不同了,所以s改变后,b并不会改变。
所以他们的区别就在于 bytes.Buffer 是重新申请了一块空间,存放生成的string变量, 而strings.Builder直接将底层的[]byte转换成了string类型返回了回来,去掉了申请空间的操作。
GO语言之bytes.buffer
bytes.Buffer
bytes.Buffer是一个缓冲byte类型的缓冲器存放着都是byte。
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缓冲器
四种创建方式:
var b bytes.Buffer //直接定义一个 Buffer 变量,而不用初始化
b1 := new(bytes.Buffer) //直接使用 new 初始化,可以直接使用
// 其它两种定义方式
func NewBuffer(buf []byte) *Buffer
func NewBufferString(s string) *Buffer
代码实现:
package main
import (
"bytes"
"fmt"
)
func main()
//第一种定义方式
var b bytes.Buffer //直接定义一个 Buffer 变量,而不用初始化
b.Write([]byte("Hello ")) // 可以直接使用
fmt.Println(b.String())
//第二种定义方式
c := new(bytes.Buffer)
c.WriteString("World")
fmt.Println(c)
//第三种定义方式
d := bytes.NewBuffer(nil)
d.WriteString("这是第三种定义方式")
fmt.Println(d.String())
//第四张定义方式
f := bytes.NewBufferString("这是第四种定义方式")
fmt.Println(f.String())
输出:
Hello
World
这是第三种定义方式
这是第四种定义方式
向Buffer中写入数据
1.Write,把字节切片p写入到buffer中去。
func main()
newBytes := []byte(" go")
//创建一个内容Learning的缓冲器
buf := bytes.NewBuffer([]byte("Learning"))
//将newBytes这个slice写到buf的尾部
buf.Write(newBytes)
fmt.Println(buf.String())
2.WriteString,使用WriteString方法,将一个字符串放到缓冲器的尾部。
func main()
newString := " go"
//创建一个string内容Learning的缓冲器
buf := bytes.NewBufferString("Learning")
//将newString这个string写到buf的尾部
buf.WriteString(newString)
fmt.Println(buf.String())
从Buffer中读取数据
1.Read,给Read方法一个容器p,读完后,p就满了,缓冲器相应的减少了,返回的n为成功读的数量。
func (b *Buffer) Read(p []byte) (n int, err error)
func main()
bufs := bytes.NewBufferString("Learning swift.")
fmt.Println("缓冲器:"+bufs.String())
l := make([]byte, 5)
//把bufs的内容读入到l内,因为l容量为5,所以只读了5个过来
bufs.Read(l)
fmt.Println("读取到的内容:"+string(l))
fmt.Println("缓冲器:"+bufs.String())
输出:
缓冲器:Learning swift.
读取到的内容:Learn
缓冲器:ing swift.
2.ReadFrom,从一个实现io.Reader接口的r,把r里的内容读到缓冲器里,n返回读的数量。
func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error)
func main()
file, _ := os.Open("d:/a.txt")
buf := bytes.NewBufferString("Learning swift.")
buf.ReadFrom(file) //将text.txt内容追加到缓冲器的尾部
fmt.Println(buf.String())
输出:
Learning swift.this is text
3.Reset,将数据清空,没有数据可读
func main()
bufs := bytes.NewBufferString("现在开始 Learning go.")
bufs.Reset()
fmt.Println(bufs.String())
声明:Nansheng.Su 发表于 2019-04-28 11:03:00 ,共计399字。
转载请署名:GO语言之bytes.buffer | www.sunansheng.com
以上是关于go语言string之Buffer与Builder的主要内容,如果未能解决你的问题,请参考以下文章
String String Buffer String Builder