Go-深入理解Buffer

深入理解Buffer

Buffer是个可以供读写的可变长字节缓冲区

数据结构

type Buffer struct {
    // buf[off : len(buf)] 内容
    buf      []byte // contents are the bytes buf[off : len(buf)]
    // 读取在&buf[off], 写入在&buf[len(buf)]
	off      int    // read at &buf[off], write at &buf[len(buf)]
	lastRead readOp // 最后一次读取操作
}

const (
    // 读取操作
    opRead      readOp = -1 // Any other read operation.
    // 非读操作
    opInvalid   readOp = 0  // Non-read operation.
    // 读取第一个字节
	opReadRune1 readOp = 1  // Read rune of size 1.
	opReadRune2 readOp = 2  // Read rune of size 2.
	opReadRune3 readOp = 3  // Read rune of size 3.
	opReadRune4 readOp = 4  // Read rune of size 4.
)

操作方法

Bytes

返回Buffer中未读取的字节

func (b *Buffer) Bytes() []byte { return b.buf[b.off:] }

Len

返回未读取的字节长度,b.Len() == len(b.Bytes())

func (b *Buffer) Len() int { return len(b.buf) - b.off }

Cap

Cap返回Buffer当前的容量长度

func (b *Buffer) Cap() int { return cap(b.buf) }

Truncate

Truncate 会丢弃除了未读的数据, 如果n==0 会丢弃所有数据

func (b *Buffer) Truncate(n int) {
	if n == 0 {
		b.Reset()
		return
	}
	b.lastRead = opInvalid
	if n < 0 || n > b.Len() {
		panic("bytes.Buffer: truncation out of range")
	}
	b.buf = b.buf[:b.off+n]
}

Reset

Reset清空缓存区数据

func (b *Buffer) Reset() {
	b.buf = b.buf[:0]
	b.off = 0
	b.lastRead = opInvalid
}

Grow

Grow 会增加buffer的容量,n不得为负数

func (b *Buffer) Grow(n int) {
	if n < 0 {
		panic("bytes.Buffer.Grow: negative count")
	}
	m := b.grow(n)
	b.buf = b.buf[:m]
}

grow

grow增加buffer的容量,保证有n个字节可以写入

func (b *Buffer) grow(n int) int {
	m := b.Len()
    // 如果buffer为空,执行reset获取空间
	if m == 0 && b.off != 0 {
		b.Reset()
	}

    // 尝试快速扩容
	if i, ok := b.tryGrowByReslice(n); ok {
		return i
    }
    // smallBufferSize = 64
    // buf为空,并且扩容的大小过小
	if b.buf == nil && n <= smallBufferSize {
		b.buf = make([]byte, n, smallBufferSize)
		return 0
	}
    c := cap(b.buf)
    // 如果buf长度+n小于等于buf容量的一半,这种只需向下滑动即可
	if n <= c/2-m {
		// We can slide things down instead of allocating a new
		// slice. We only need m+n <= c to slide, but
		// we instead let capacity get twice as large so we
        // don't spend all our time copying.
        // 丢弃已读的数据
		copy(b.buf, b.buf[b.off:])
	} else if c > maxInt-c-n {
        // 要分配的数据太大了
		panic(ErrTooLarge)
	} else {
        // 没有足够的空间,直接分配,分配后的大小是2*c + n
        buf := makeSlice(2*c + n)
        // 丢弃已读数据
		copy(buf, b.buf[b.off:])
		b.buf = buf
	}

    // 重置off
	b.off = 0
	b.buf = b.buf[:m+n]
	return m
}

tryGrowByReslice

tryGrowByReslice返回可写入字节的索引以及是否扩容成功,快速扩容方案

func (b *Buffer) tryGrowByReslice(n int) (int, bool) {
    // 如果buf空闲的数量大于要扩容的大小
	if l := len(b.buf); n <= cap(b.buf)-l {
        // 快速扩容,reslice
		b.buf = b.buf[:l+n]
		return l, true
	}
	return 0, false
}

Write

Write写入数据到buffer中,必要情况下会扩容buffer,如果err == nil,n == len(p)

func (b *Buffer) Write(p []byte) (n int, err error) {
	b.lastRead = opInvalid
	m, ok := b.tryGrowByReslice(len(p))
	if !ok {
		m = b.grow(len(p))
	}
	return copy(b.buf[m:], p), nil
}

ReadFrom

ReadFrom从r中读取直到EOF,并append到buffer中,如果需要,会扩容buffer。返回的n是读取的字节数,除了EOF的错误都会fan’hui

func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) {
	b.lastRead = opInvalid
	for {
		i := b.grow(MinRead) // MinRead = 512
		b.buf = b.buf[:i]
		m, e := r.Read(b.buf[i:cap(b.buf)])
		if m < 0 {
			panic(errNegativeRead)
		}

		b.buf = b.buf[:i+m]
		n += int64(m)
		if e == io.EOF {
			return n, nil // e is EOF, so return nil explicitly
		}
		if e != nil {
			return n, e
		}
	}
}

WriteTo

WriteTo 写入数据到w中,直接buffer中数据耗尽,返回写入的字节数和写入过程中遇到的错误

func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) {
	b.lastRead = opInvalid
	if nBytes := b.Len(); nBytes > 0 {
		m, e := w.Write(b.buf[b.off:])
		if m > nBytes {
			panic("bytes.Buffer.WriteTo: invalid Write count")
		}
		b.off += m
		n = int64(m)
		if e != nil {
			return n, e
		}
		// all bytes should have been written, by definition of
		// Write method in io.Writer
		if m != nBytes {
			return n, io.ErrShortWrite
		}
	}
	// Buffer 已经写完,reset
	b.Reset()
	return n, nil
}

Read

Read会读取下n个字节直接buffer耗尽,返回读取的字节和读取遇到的错误,如果buffer为空,错误返回EOF

func (b *Buffer) Read(p []byte) (n int, err error) {
	b.lastRead = opInvalid
	if b.empty() {
		// Buffer is empty, reset to recover space.
		b.Reset()
		if len(p) == 0 {
			return 0, nil
		}
		return 0, io.EOF
	}
	n = copy(p, b.buf[b.off:])
	b.off += n
	if n > 0 {
		b.lastRead = opRead
	}
	return n, nil
}

Next

Next返回下n个字节数据,如果buffer未读字节数小于n,则返回整个buffer,

func (b *Buffer) Next(n int) []byte {
	b.lastRead = opInvalid
	m := b.Len()
	if n > m {
		n = m
	}
	data := b.buf[b.off : b.off+n]
	b.off += n
	if n > 0 {
		b.lastRead = opRead
	}
	return data
}

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 {
		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
}

总结

buffer提供了可扩容的缓冲池,如果数据比较大,我们已经提前申请好相应的buffer,以免buffer多次扩容。


2021-06-27 09:12 +0800