1. 程式人生 > >go原生庫的中bytes.Buffer

go原生庫的中bytes.Buffer

1 bytes.Buffer定義

bytes.Buffer提供可擴容的位元組緩衝區,實質是對切片的封裝;結構中包含一個64位元組的小切片,避免小記憶體分配:

// 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)]--->指示讀指標
	bootstrap [64]byte // memory to hold first slice; helps small buffers avoid allocation.
	lastRead  readOp   // last read operation, so that Unread* can work correctly.
}

2 初始化bytes.Buffer的方法

1) var buf bytes.Buffer ->定義一個空的位元組緩衝區

2) func NewBuffer(buf []byte) *Buffer { return &Buffer{buf: buf} } -->將位元組切片初始化為緩衝區

3) func NewBufferString(s string) *Buffer {return &Buffer{buf: []byte(s)}} -->將字串初始化為緩衝區

3 提供的主要API函式

1)寫位元組流資料到緩衝區

// Write appends the contents of p to the buffer, growing the buffer as
// needed. The return value n is the length of p; err is always nil. If the
// buffer becomes too large, Write will panic with ErrTooLarge.
func (b *Buffer) Write(p []byte) (n int, err error) {
	b.lastRead = opInvalid
	m := b.grow(len(p))
	return copy(b.buf[m:], p), nil
}

2)寫字串到緩衝區

// WriteString appends the contents of s to the buffer, growing the buffer as
// needed. The return value n is the length of s; err is always nil. If the
// buffer becomes too large, WriteString will panic with ErrTooLarge.
func (b *Buffer) WriteString(s string) (n int, err error) {
	b.lastRead = opInvalid
	//返回寫入的index
	m := b.grow(len(s))
	return copy(b.buf[m:], s), nil
}

3)從緩衝區中讀取資料

// Read reads the next len(p) bytes from the buffer or until the buffer
// is drained. The return value n is the number of bytes read. If the
// buffer has no data to return, err is io.EOF (unless len(p) is zero);
// otherwise it is nil.
func (b *Buffer) Read(p []byte) (n int, err error) {
	b.lastRead = opInvalid
	if b.off >= len(b.buf) {
		// Buffer is empty, reset to recover space.
		b.Truncate(0)
		if len(p) == 0 {
			return
		}
		return 0, io.EOF
	}
	n = copy(p, b.buf[b.off:])
	b.off += n
	if n > 0 {
		b.lastRead = opRead
	}
	return
}

4)從緩衝區中讀取字串,直到分隔符delim 位置

// ReadString reads until the first occurrence of delim in the input,
// returning a string containing the data up to and including the delimiter.
// If ReadString encounters an error before finding a delimiter,
// it returns the data read before the error and the error itself (often io.EOF).
// ReadString returns err != nil if and only if the returned data does not end
// in delim.
func (b *Buffer) ReadString(delim byte) (line string, err error) {
	slice, err := b.readSlice(delim)
	return string(slice), err
}

5)將未被讀取的位元組資料返回

// Bytes returns a slice of length b.Len() holding the unread portion of the buffer.
// The slice is valid for use only until the next buffer modification (that is,
// only until the next call to a method like Read, Write, Reset, or Truncate).
// The slice aliases the buffer content at least until the next buffer modification,
// so immediate changes to the slice will affect the result of future reads.
func (b *Buffer) Bytes() []byte { return b.buf[b.off:] }

6)將未被讀取的位元組資料以字串形式返回

// String returns the contents of the unread portion of the buffer
// as a string. If the Buffer is a nil pointer, it returns "<nil>".
func (b *Buffer) String() string {
	if b == nil {
		// Special case, useful in debugging.
		return "<nil>"
	}
	return string(b.buf[b.off:])
}

7)返回緩衝區當前容量

// Cap returns the capacity of the buffer's underlying byte slice, that is, the
// total space allocated for the buffer's data.
func (b *Buffer) Cap() int { return cap(b.buf) }

8)返回未被讀取的位元組資料大小

// Len returns the number of bytes of the unread portion of the buffer;
// b.Len() == len(b.Bytes()).
func (b *Buffer) Len() int { return len(b.buf) - b.off }

4 bytes.Buffer自動擴容機制

當向緩衝區寫入資料時,首先會檢查當前容量是否滿足需求,如果不滿足分三種情況處理:

1)當前內建緩衝區切片buf為空,且寫入資料量小於bootstrap的大小(64位元組),則bootstrap作為buf

2)當前未讀資料長度+新寫入資料長度小於等於緩衝區容量的1/2,則挪動資料(將未讀的資料放到已讀資料位置)

3)以上條件不滿足,只能重新分配切片,容量設定為2*cap(b.buf) + n,即兩倍原來的緩衝區容量+寫入資料量大小

// grow grows the buffer to guarantee space for n more bytes.
// It returns the index where bytes should be written.
// If the buffer can't grow it will panic with ErrTooLarge.
func (b *Buffer) grow(n int) int {
	m := b.Len()
	// If buffer is empty, reset to recover space.
	if m == 0 && b.off != 0 {
		b.Truncate(0)
	}
	//如果需要的容量大於現在的容量--->
	if len(b.buf)+n > cap(b.buf) {
		var buf []byte
		//現有的預備64byte可以滿足
		if b.buf == nil && n <= len(b.bootstrap) {
			buf = b.bootstrap[0:]
			//實際需要的小於本身切片容量
		} else if m+n <= cap(b.buf)/2 {
			// We can slide things down instead of allocating a new
			// slice. We only need m+n <= cap(b.buf) 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:])
			buf = b.buf[:m]
		} else {
			// not enough space anywhere
			//不夠,那就分配2倍加n的容量
			buf = makeSlice(2*cap(b.buf) + n)
			copy(buf, b.buf[b.off:])
		}
		b.buf = buf
		b.off = 0
	}
	b.buf = b.buf[0 : b.off+m+n]
	return b.off + m
}

5 bytes.Buffer的侷限

bytes.Buffer提供了對切片的初步封裝,但也沒做太多的事;對於已讀的資料無法操作。