buffer 原始碼包閱讀
這裡是我的語雀 https://www.yuque.com/abs
buffer.go
Overview
一圖勝千言
核心函式
Buffer 結構
這是 buffer 的內部結構
buf 位元組切片,用來儲存 buffer 的內容
off 是代表從哪裡開始讀
bootstrap 用來作為位元組切片過小的時候防止多次申請空間減小開銷
lastRead 用來記錄上一次的操作
// 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 的零值是空的 buf
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.
// FIXME: it would be advisable to align Buffer to cachelines to avoid false
// sharing.
}
Grow(n int)
申請擴充套件緩衝區
// Grow grows the buffer's capacity, if necessary, to guarantee space for
// another n bytes. After Grow(n), at least n bytes can be written to the
// buffer without another allocation.
// If n is negative, Grow will panic.
// If the buffer can't grow it will panic with ErrTooLarge.
// 增加容量 n byte
func (b *Buffer) Grow(n int) {
if n < 0 {
panic("bytes.Buffer.Grow: negative count")
}
m := b.grow(n)
b.buf = b.buf[:m]
}
WriteString(s string) (n int, err error)
向 buffer 中寫字串
// 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.
// 直接寫 string 也行,同時自動擴充套件
func (b *Buffer) WriteString(s string) (n int, err error) {
b.lastRead = opInvalid
//先嚐試不用擴充套件容量的寫法
m, ok := b.tryGrowByReslice(len(s))
if !ok {
m = b.grow(len(s))
}
// copy 可以直接把 string 型別作為 位元組切片拷貝過去
return copy(b.buf[m:], s), nil
}
也有寫位元組切片的形式 Write(p []byte) (n int, err error)
ReadFrom(r io.Reader) (n int64, err error)
從 io.Reader 讀取資料到 buffer 中
// ReadFrom reads data from r until EOF and appends it to the buffer, growing
// the buffer as needed. The return value n is the number of bytes read. Any
// error except io.EOF encountered during the read is also returned. If the
// buffer becomes too large, ReadFrom will panic with ErrTooLarge.
// 從實現了 io.Reader 介面的 r 中讀取到 EOF 為止,如果超出了 maxInt 那麼大就會返回太
// 大不能通過一個 [maxInt]byte 位元組切片來儲存了
func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) {
b.lastRead = opInvalid
for {
i := b.grow(MinRead)
// grow 申請了 n 個空間之後,會將 buffer 中的位元組切片延長長度到 n 個位元組之後
// 所以需要重新賦值一下長度,避免一些誤解,保證長度都是有效資料提供的
b.buf = b.buf[:i]
// 將 r 中的資料讀到 buffer 中去
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(w io.Writer) (n int64, err error)
向 io.Writer 中寫資料
// WriteTo writes data to w until the buffer is drained or an error occurs.
// The return value n is the number of bytes written; it always fits into an
// int, but it is int64 to match the io.WriterTo interface. Any error
// encountered during the write is also returned.
func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) {
b.lastRead = opInvalid
if nBytes := b.Len(); nBytes > 0 {
//從 off 開始讀的地方算起,全部寫到 io.Writer 中去
m, e := w.Write(b.buf[b.off:])
//寫的多了就報錯
if m > nBytes {
panic("bytes.Buffer.WriteTo: invalid Write count")
}
//記錄寫過了多少,位移 offset 指標
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 is now empty; reset.
// 寫完之後重置
b.Reset()
return n, nil
}
ReadBytes(delim byte) (line []byte, err error)
用來讀到終止符就結束,返回的是一個 line 位元組切片包含終止符前的資料
// ReadBytes reads until the first occurrence of delim in the input,
// returning a slice containing the data up to and including the delimiter.
// If ReadBytes encounters an error before finding a delimiter,
// it returns the data read before the error and the error itself (often io.EOF).
// ReadBytes returns err != nil if and only if the returned data does not end in
// delim.
// 讀取到終止符為止,就結束
func (b *Buffer) ReadBytes(delim byte) (line []byte, err error) {
slice, err := b.readSlice(delim)
// return a copy of slice. The buffer's backing array may
// be overwritten by later calls.
line = append(line, slice...)
return line, err
}
NewBuffer(buf []byte) *Buffer
用來新建一個新的 Buffer ,其實也可以使用 new 和 var 來宣告
// NewBuffer creates and initializes a new Buffer using buf as its
// initial contents. The new Buffer takes ownership of buf, and the
// caller should not use buf after this call. NewBuffer is intended to
// prepare a Buffer to read existing data. It can also be used to size
// the internal buffer for writing. To do that, buf should have the
// desired capacity but a length of zero.
//
// In most cases, new(Buffer) (or just declaring a Buffer variable) is
// sufficient to initialize a Buffer.
// 通過位元組切片建立一個 buffer ,位元組切片會保留初始值
// 在渴望容量但是長度為 0?的情況下
// 也可以當作核心的 buffer 來寫入
func NewBuffer(buf []byte) *Buffer { return &Buffer{buf: buf} }
同時也有通過 string 型別的實現**func NewBufferString(s string) *Buffer {return &Buffer{buf: []byte(s)}}**
總結
緩衝區,實現了大小控制,位元組切片和 string 型別的讀寫,同時還對情況進行了優化,比如存在 bootstrap,比如 grow 函式中的多次檢定。適合多讀精讀來學習
相關文章
- 【原始碼閱讀】AndPermission原始碼閱讀原始碼
- 第 31 期 flag 包原始碼閱讀原始碼
- Spring Webflux 原始碼閱讀之 accept包SpringWebUX原始碼
- Python原始碼閱讀-閉包的實現Python原始碼
- 【原始碼閱讀】Glide原始碼閱讀之with方法(一)原始碼IDE
- 【原始碼閱讀】Glide原始碼閱讀之into方法(三)原始碼IDE
- ReactorKit原始碼閱讀React原始碼
- AQS原始碼閱讀AQS原始碼
- CountDownLatch原始碼閱讀CountDownLatch原始碼
- HashMap 原始碼閱讀HashMap原始碼
- delta原始碼閱讀原始碼
- 原始碼閱讀-HashMap原始碼HashMap
- NGINX原始碼閱讀Nginx原始碼
- Mux 原始碼閱讀UX原始碼
- HashMap原始碼閱讀HashMap原始碼
- fuzz原始碼閱讀原始碼
- RunLoop 原始碼閱讀OOP原始碼
- express 原始碼閱讀Express原始碼
- muduo原始碼閱讀原始碼
- stack原始碼閱讀原始碼
- 【原始碼閱讀】Glide原始碼閱讀之load方法(二)原始碼IDE
- PostgreSQL 原始碼解讀(3)- 如何閱讀原始碼SQL原始碼
- JDK原始碼閱讀:Object類閱讀筆記JDK原始碼Object筆記
- Laravel 原始碼閱讀 - QueueLaravel原始碼
- Vollery原始碼閱讀(—)原始碼
- 使用OpenGrok閱讀原始碼原始碼
- 如何閱讀Java原始碼?Java原始碼
- 原始碼閱讀技巧篇原始碼
- 如何閱讀框架原始碼框架原始碼
- 再談原始碼閱讀原始碼
- Laravel 原始碼閱讀 - EloquentLaravel原始碼
- 如何閱讀jdk原始碼?JDK原始碼
- express 原始碼閱讀(全)Express原始碼
- Vuex原始碼閱讀分析Vue原始碼
- React原始碼閱讀:setStateReact原始碼
- ArrayList原始碼閱讀(增)原始碼
- ThreadLocal原始碼閱讀thread原始碼
- snabbdom 原始碼閱讀分析原始碼