последовательность
Недавно я собираюсь изучить стандартную библиотеку golang, подробно прочитать исходный код, в этом каталоге записан процесс обучения и опыт.
языкioutil
Пакет предоставляет множество удобных наборов инструментов для io-операций, в этой статье в основном подробно анализируется именно он.ReadAll
Исходный код реализации метода.
ReadAll
Это очень распространенный метод одноразового чтения.io.Reader
данные в нем.
реализация исходного кода
1. ReadAll
Читая исходный код ниже, мы можем обнаружить, чтоReadAll
На самом деле вызывается неэкспортируемый метод, и мы отслеживаем его шаг за шагом
// ReadAll reads from r until an error or EOF and returns the data it read.
// A successful call returns err == nil, not err == EOF. Because ReadAll is
// defined to read from src until EOF, it does not treat an EOF from Read
// as an error to be reported.
// ReadAll从r读取数据直到EOF或遇到error,返回读取的数据和遇到的错误。
// 成功的调用返回的err为nil而非EOF。
// 因为本函数定义为读取r直到EOF,它不会将读取返回的EOF视为应报告的错误。
func ReadAll(r io.Reader) ([]byte, error) {
return readAll(r, bytes.MinRead)
}
2. readAll
Читая этот код функции, вы можете найти,ioutil.ReadAll
по существу использоватьbytes.buffer
Реализовано, в котором делается два вызоваbytes.buffer
метод, метод для инициализацииbuffer
емкость, один для чтения всехio.Reader
данные
Кроме того, мы также можем узнать, как использовать паническое восстановление в ходу.buffer
Среди них, если не может быть выделено достаточно памяти, она будет напрямуюpanic bytes.ErrTooLarge
Ошибка, однако, этот метод мы ожидаем вернуть эту ошибку, на этот раз можно использоватьdefer recover
отpanic
восстановление
// readAll reads from r until an error or EOF and returns the data it read
// from the internal buffer allocated with a specified capacity.
// readAll从r读取到一个错误或EOF,并返回从指定容量分配的内部缓冲区中读取的数据。
func readAll(r io.Reader, capacity int64) (b []byte, err error) {
// 新建了一个buffer
var buf bytes.Buffer
// If the buffer overflows, we will get bytes.ErrTooLarge.
// Return that as an error. Any other panic remains.
// 如果buffer溢出了,会得到一个bytes.ErrTooLarge的错误
// 如果得到的是bytes.ErrTooLarge错误,将其返回,其他panic错误,仍然panic
defer func() {
e := recover()
if e == nil {
return
}
if panicErr, ok := e.(error); ok && panicErr == bytes.ErrTooLarge {
err = panicErr
} else {
panic(e)
}
}()
// 判断capacity的值是否超过了int类型的上限
if int64(int(capacity)) == capacity {
// 向buffer当中增加capacity的容量
buf.Grow(int(capacity))
}
// 使用buffer ReadFrom 方法读取所有的io.Reader数据
_, err = buf.ReadFrom(r)
return buf.Bytes(), err
}
3. buffer
видетьbuffer
Реализация связанных функций, давайте сначала посмотримbuffer
Определение , иначе можно запутаться B
В основном используются два поля, одноbuf
,buf
контент используетсяoff
прибытьlen(buf)
из,off
Предыдущее представление прочитало данные,off
представляет текущую позицию,buffer
изwrite和read
методы начнутся с этого места
// 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是一个实现了读写方法的可变大小的字节缓冲。
// 本类型的零值是一个空的可用于读写的缓冲。
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.
// FIXME: lastRead can fit in a single byte
// memory to hold first slice; helps small buffers avoid allocation.
// FIXME: it would be advisable to align Buffer to cachelines to avoid false
// sharing.
bootstrap [64]byte
}
4. buffer.Grow
Этот метод в основном используется для увеличения памяти буфера, но фактически вызывает неэкспортируемыйgrow
метод
// 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字节的剩余空间。
// 调用Grow(n)后至少可以向缓冲中写入n字节数据而无需申请内存。
// 如果n小于零或者不能增加容量都会panic ErrTooLarge 错误。
func (b *Buffer) Grow(n int) {
if n < 0 {
panic("bytes.Buffer.Grow: negative count")
}
m := b.grow(n)
b.buf = b.buf[0:m]
}
5. buffer.ReadFrom
В основном посмотрите на реализацию этого метода, который реализуетio.Reader
Прочитать все данные.
Схема:
// 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.
// ReadFrom从r中读取数据直到结束并将读取的数据写入缓冲中,如必要会增加缓冲容量。
// 返回值n为从r读取并写入b的字节数;会返回读取时遇到的除了io.EOF之外的错误。
// 如果缓冲太大,ReadFrom会采用错误值ErrTooLarge引发panic。
func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) {
// const opInvalid = 0 // Non-read operation. 表示之前没有读操作
b.lastRead = opInvalid
// If buffer is empty, reset to recover space.
// 如果缓冲区为空,重置为恢复空间。
if b.off >= len(b.buf) {
b.Reset()
}
// 循环读取io.Reader 的数据
for {
// 判断当前剩余空间是否小于MinRead,MinRead = 512
if free := cap(b.buf) - len(b.buf); free < MinRead {
// not enough space at end
// 空间不足
// 新建一个buf
newBuf := b.buf
// 判断实际剩余容量是否小于MinRead = 512
if b.off+free < MinRead {
// not enough space using beginning of buffer;
// double buffer capacity
// 实际剩余空间不足,分配双倍的缓冲空间,缓冲的最小值为MinRead所以加上一个MinRead,避免双倍之后仍然比MinRead小
// makeSlice函数用于分配缓冲空间,如果分配失败会panic ErrTooLarge 错误
newBuf = makeSlice(2*cap(b.buf) + MinRead)
}
// 将原有buf数据复制到新的buf
copy(newBuf, b.buf[b.off:])
// len(b.buf)-b.off 就等于buf当前内容的长度
// 例子: a:=make([]byte,20)
// b:=a[:10]
// len(b) // 10
// cap(b) //20
b.buf = newBuf[:len(b.buf)-b.off]
// 将off置0
b.off = 0
}
// 从io.Reader当中读取数据,传入buf的剩余空间
// 第一种情况,数据读取完毕,返回读取长度m以及,io.EOF错误
// 第二种情况, 数据未读完,遇到错误
// 第三种情况,数据未读完,缓冲区容量不够,返回读取数据长度m以及nil
m, e := r.Read(b.buf[len(b.buf):cap(b.buf)])
// 只获取有数据的buf,无数据的空间转化为cap
b.buf = b.buf[0 : len(b.buf)+m]
n += int64(m)
// 数据读取完毕跳出循环
if e == io.EOF {
break
}
// 遇到错误返回
if e != nil {
return n, e
}
}
return n, nil // err is EOF, so return nil explicitly
}