последовательность
Недавно я собираюсь изучить стандартную библиотеку 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
}