内容
1 bytes.Buffer
2 strings.Builder
3 bufio包
前言
bytes.Buffer strings.Builder和bufio都是golang中经常使用的提供了缓冲池的数据结构,他们内部都是封装了一个[]byte, 可以用来高效的操作字节切片、字符串和io操作
一 byte.Buffer
byte.Buffer是一个简单字节缓冲池,内部包了一个字节数组,在某些频繁io的操作中,可以使用buffer来做一个读取或是写入的缓冲池,来提高效率
// 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.
type Buffer struct {
buf []byte // contents are the bytes buf[off : len(buf)]
off int // read at &buf[off], write at &buf[len(buf)]
lastRead readOp // last read operation, so that Unread* can work correctly.
}
二 strings.builder
strings.builder可以高效的写入、拼接字符串,其内部封装了一个字节数组,写入时其实是将传入的字节append到内部的字节数组上
// A Builder is used to efficiently build a string using Write methods.
// It minimizes memory copying. The zero value is ready to use.
// Do not copy a non-zero Builder.
type Builder struct {
addr *Builder // of receiver, to detect copies by value
buf []byte
}
// Write appends the contents of p to b's buffer.
// Write always returns len(p), nil.
func (b *Builder) Write(p []byte) (int, error) {
b.copyCheck()
b.buf = append(b.buf, p...)
return len(p), nil
}
- 当builder已经写入值后,或是严格来说其内部切片已经不为nil后,不允许拷贝builder,因为builder内部实际是使用一个切片,拷贝builder后,它们底层还是共享同一个数组,会发生覆盖操作,例如下面这样是不允许的
builder := strings.Builder{}
builder.WriteString("haha")
builder2 := builder
builder2.WriteString("ww")
builder2.WriteString会调用copyCheck检查内部切片是否为nil,不为nil直接panic
func (b *Builder) copyCheck() {
if b.addr == nil {
// This hack works around a failing of Go's escape analysis
// that was causing b to escape and be heap allocated.
// See issue 23382.
// TODO: once issue 7921 is fixed, this should be reverted to
// just "b.addr = b".
b.addr = (*Builder)(noescape(unsafe.Pointer(b)))
} else if b.addr != b {
panic("strings: illegal use of non-zero Builder copied by value")
}
}
三 bufio
bufio包提供了有缓冲的io,它定义了两个结构体,分别是Reader和Writer, 它们也分别实现了io包中io.Reader和io.Writer接口, 通过传入一个io.Reader的实现对象和一个缓冲池大小参数,可以构造一个bufio.Reader对象,根据bufio.Reader的相关方法便可读取io.Reader中数据流,因为带有缓冲池,读数据会先读到缓冲池,再次读取会先去缓冲池读取,这样减少了io操作,提高了效率;
// 构造Reader对象
func NewReaderSize(rd io.Reader, size int) *Reader {}
// Reader implements buffering for an io.Reader object.
type Reader struct {
buf []byte
rd io.Reader // reader provided by the client
r, w int // buf read and write positions
err error
lastByte int // last byte read for UnreadByte; -1 means invalid
lastRuneSize int // size of last rune read for UnreadRune; -1 means invalid
}
// Writer implements buffering for an io.Writer object.
type Writer struct {
err error
buf []byte
n int
wr io.Writer
}
func (b *Reader) Read(p []byte) (n int, err error) 具体读取流程如下:
- 当缓存区有内容的时,将缓存区内容读取到p并清空缓存区;
- 当缓存区没有内容的时候且len(p)>len(buf),即要读取的内容比缓存区还要大,直接读取文件;
- 当缓存区没有内容的时候且len(p)<len(buf),即要读取的内容比缓存区小,缓存区从文件读取内容充满缓存区,并将p填满(此时缓存区有剩余内容)
- 以后再次读取时缓存区有内容,将缓存区内容全部填入p并清空缓存区;
func (b *Writer) Write(p []byte) (nn int, err error) 具体写入流程如下:
- 判断buf中可用容量是否可以放下 p;如果能放下,直接把p拼接到buf后面,即把内容放到缓冲区
- 如果缓冲区的可用容量不足以放下,且此时缓冲区是空的,直接把p写入文件即可
- 如果缓冲区的可用容量不足以放下,且此时缓冲区有内容,则用p把缓冲区填满,把缓冲区所有内容写入文件,并清空缓冲区;
引用:
- golang中bufio实现原理:https://blog.csdn.net/LiangWenT/article/details/78995468
- go语言标准库-io : http://books.studygolang.com/The-Golang-Standard-Library-by-Example/chapter01/01.4.html#14-bufio-%E2%80%94-%E7%BC%93%E5%AD%98io
有疑问加站长微信联系(非本文作者)