Vaya a aprender el código fuente: paquete bufio-1.1-bufio.go-(1)

documentación oficial del paquete bufio

Ir al directorio de índice de aprendizaje del código fuente

1. La función del paquete bufio.

bufioEl paquete es un conjunto de herramientas para funciones de E/S almacenadas en búfer proporcionadas en la biblioteca estándar del lenguaje Go. Se utiliza principalmente para proporcionar soporte de almacenamiento en búfer para operaciones de E/S y puede ayudar a mejorar el rendimiento y la eficiencia de las operaciones de E/S.

bufioEl paquete proporciona un conjunto de herramientas poderosas para hacer que la lectura y escritura de datos sean más eficientes y flexibles, y puede reducir la ocupación frecuente de los recursos del sistema. Es especialmente adecuado para procesar grandes cantidades de datos o E/S que requieren un alto rendimiento. .

En concreto, bufioel paquete proporciona las siguientes funciones y funciones:

  1. Lectura tamponada :

    • bufioReaderEl paquete proporciona una función de lectura almacenada en búfer a través del tipo, que puede reducir la cantidad de lecturas reales de la fuente de datos subyacente (como archivos, conexiones de red, etc.), mejorando así el rendimiento de lectura.
  2. Escritura almacenada en búfer :

    • A través Writerdel tipo, bufioel paquete admite escrituras en búfer, que almacenan datos temporalmente en la memoria, lo que reduce la cantidad de escrituras reales en el destino de datos subyacente y mejora el rendimiento de escritura.
  3. Manejo eficiente de bytes :

    • Proporciona métodos de procesamiento eficientes para bytes, como lectura y escritura de bytes, y otras operaciones basadas en bytes, que son muy útiles para procesar datos binarios.
  4. Escaneo de líneas :

    • bufio.ScannerEl tipo puede dividir texto fácilmente y admitir el escaneo de líneas. Los usuarios pueden definir sus propias funciones de segmentación para manejar fácilmente varios formatos de texto.
  5. Mejoras de flexibilidad y rendimiento :

    • Al almacenar los datos en la memoria, se reduce la cantidad de llamadas al sistema, mejorando así la eficiencia y el rendimiento de las operaciones de E/S.

2.bufio.go

1. Propósito y estructura básica del paquete bufio.

// Package bufio 实现了带缓冲的 I/O 操作。它封装了一个 io.Reader 或 io.Writer
// 对象,创建了另一个实现相同接口的对象(Reader 或 Writer),但提供了缓冲和
// 一些文本 I/O 的辅助功能。

package bufio

import (
	"bytes"
	"errors"
	"io"
	"strings"
	"unicode/utf8"
)

// 默认缓冲区大小
const (
	defaultBufSize = 4096
)

var (
	// ErrInvalidUnreadByte 表示对 UnreadByte 的无效使用
	ErrInvalidUnreadByte = errors.New("bufio: invalid use of UnreadByte")
	// ErrInvalidUnreadRune 表示对 UnreadRune 的无效使用
	ErrInvalidUnreadRune = errors.New("bufio: invalid use of UnreadRune")
	// ErrBufferFull 表示缓冲区已满
	ErrBufferFull        = errors.New("bufio: buffer full")
	// ErrNegativeCount 表示计数为负值
	ErrNegativeCount     = errors.New("bufio: negative count")
)

// 缓冲输入。

// Reader 实现了对 io.Reader 对象的缓冲。它包装了一个由客户端提供的 io.Reader,
// 创建了另一个对象(Reader),该对象同样实现了接口,但提供了缓冲和一些文本 I/O 的帮助。
type Reader struct {
    
    
	buf          []byte    // 缓冲区
	rd           io.Reader // 客户端提供的 reader
	r, w         int       // buf 的读写位置
	err          error     // 错误信息
	lastByte     int       // 上一次读取的字节,用于 UnreadByte;-1 表示无效
	lastRuneSize int       // 上一次读取的 rune 大小,用于 UnreadRune;-1 表示无效
}

// 最小读取缓冲区大小
const minReadBufferSize = 16
// 最大连续空读取次数
const maxConsecutiveEmptyReads = 100

// NewReaderSize 返回一个新的 [Reader],其缓冲区大小至少为指定大小。如果参数 io.Reader
// 已经是一个拥有足够大大小的 [Reader],则返回底层 [Reader]。
func NewReaderSize(rd io.Reader, size int) *Reader {
    
    
	// 它已经是一个 Reader 吗?
	b, ok := rd.(*Reader)
	if ok && len(b.buf) >= size {
    
    
		return b
	}
	r := new(Reader)
	r.reset(make([]byte, max(size, minReadBufferSize)), rd)
	return r
}

// NewReader 返回一个新的 [Reader],其缓冲区大小为默认大小。
func NewReader(rd io.Reader) *Reader {
    
    
	return NewReaderSize(rd, defaultBufSize)
}

Los comentarios anteriores explican bufioel propósito y la estructura básica del paquete.

Una explicación más detallada:

  • bufioEl paquete implementa operaciones de E/S almacenadas en búfer para mejorar el rendimiento y la eficiencia de las operaciones de E/S.
  • ReaderUna estructura es io.Readeruna implementación almacenada en búfer de un objeto. Contiene un búfer , un objeto bufproporcionado por el cliente y campos como ubicaciones de lectura y escritura e información de error.io.Readerrd
  • constSe declaran algunas constantes, como el tamaño del búfer predeterminado, el tamaño mínimo del búfer de lectura y el número máximo de lecturas vacías consecutivas.
  • varAlgunas variables de error se declaran para representar Readercondiciones de error que pueden ocurrir durante el uso.
  • NewReaderSizeLa función devuelve uno nuevo Readercon un tamaño de búfer de al menos el tamaño especificado. Si el argumento io.Readerya tiene un tamaño suficientemente grande Reader, se devuelve el subyacente Reader.
  • NewReaderLa función devuelve uno nuevo Readercon el tamaño de búfer predeterminado.

2. Tamaño: devuelve el tamaño del búfer subyacente.

Esta parte del código define Sizeun método que devuelve Readerel tamaño del búfer subyacente en una estructura, en bytes.

// Size 返回底层缓冲区的大小(以字节为单位)。
func (b *Reader) Size() int {
    
     return len(b.buf) }

explicar:

  • SizeUn método es Readerun método de una estructura, su receptor es by su tipo es Reader.
  • El cuerpo del método es que return len(b.buf)devuelve la longitud del campo ben la estructura buf, que es el tamaño del búfer subyacente.

efecto:

  • El propósito de este método es proporcionar Readeruna interfaz para el acceso externo al tamaño del búfer subyacente de la estructura.

3. Restablecer: restablecer el estado del búfer y leer la fuente

Esta parte del código define Resetmétodos que restablecen Readerel estado de la estructura y cambian el búfer para rleer desde una nueva fuente de lectura.

// Reset 丢弃任何已缓存的数据,重置所有状态,并切换缓冲区以从读取源 r 进行读取。
// 在 [Reader] 的零值上调用 Reset 会将内部缓冲区初始化为默认大小。
// 调用 b.Reset(b)(即将 [Reader] 重置为自身)不会执行任何操作。
func (b *Reader) Reset(r io.Reader) {
    
    
    // 如果将读取源 r 传递给 NewReader,NewReader 将返回 r。
    // 代码的不同层可能会这样做,然后稍后将 r 传递给 Reset。在这种情况下避免无限递归。
    if b == r {
    
    
        return
    }
    // 如果缓冲区为空,则将其初始化为具有默认大小的新字节切片。
    if b.buf == nil {
    
    
        b.buf = make([]byte, defaultBufSize)
    }
    // 调用 reset 方法,将缓冲区、读取源以及其他状态重置。
    b.reset(b.buf, r)
}

explicar:

  • ResetUn método es Readerun método de una estructura, su receptor es by su tipo es Reader.
  • El cuerpo principal del método incluye los siguientes pasos clave:
    1. Evite la recursividad infinita: si es la misma que bla nueva fuente de lectura r, regrese directamente para evitar la recursividad infinita.
    2. Inicializar búfer: si bufel campo es nil, inicialícelo en un nuevo segmento de bytes con el tamaño predeterminado.
    3. Llame al método de reinicio: llame resetal método para restablecer el estado del búfer, la fuente de lectura, el último byte y el tamaño de la última runa.
// reset 方法用于具体执行 [Reader] 结构体的重置,将各个字段设置为新的状态。
func (b *Reader) reset(buf []byte, r io.Reader) {
    
    
    *b = Reader{
    
    
        buf:          buf,
        rd:           r,
        lastByte:     -1,
        lastRuneSize: -1,
    }
}

Este resetmétodo interno se utiliza para realizar específicamente Readerel restablecimiento de la estructura y establecer cada campo en el nuevo estado.

efecto:

  • ResetReaderLa función de este método es restablecer el estado de la estructura para que se puedan leer nuevos datos nuevamente cuando se cambia la fuente de lectura o cuando es necesario descartar cualquier dato almacenado en caché .
  • Si Resetlo pasado cuando se llama al método es el mismo que rel actual b, significa que está intentando restablecerlo Readera sí mismo y regresará directamente sin ninguna operación.
  • Cuando Readeres un valor cero (no NewReaderinicializado con), la llamada Resetinicializa el búfer interno al tamaño predeterminado.

4. llenar: llenar el búfer

Esta parte del código define fillmétodos para leer nuevos fragmentos de datos en el búfer.

var errNegativeRead = errors.New("bufio: reader returned negative count from Read")

// fill 读取一个新的数据块填充到缓冲区中。
func (b *Reader) fill() {
    
    
    // 将现有数据滑动到开头。
    if b.r > 0 {
    
    
        copy(b.buf, b.buf[b.r:b.w])
        b.w -= b.r
        b.r = 0
    }

    // 如果缓冲区已满,则抛出 panic。
    if b.w >= len(b.buf) {
    
    
        panic("bufio: tried to fill full buffer")
    }

    // 读取新数据:尝试有限次数。
    for i := maxConsecutiveEmptyReads; i > 0; i-- {
    
    
        // 从读取源 b.rd 中读取新的数据块到缓冲区中。
        n, err := b.rd.Read(b.buf[b.w:])
        // 如果读取的字节数 n 小于零,抛出 panic,表示读取返回了负数。
        if n < 0 {
    
    
            panic(errNegativeRead)
        }
        // 将写指针 b.w 向前移动,表示成功读取了 n 个字节。
        b.w += n
        // 如果出现错误,将错误存储在 b.err 中,并结束方法。
        if err != nil {
    
    
            b.err = err
            return
        }
        // 如果成功读取了至少一个字节,退出循环。
        if n > 0 {
    
    
            return
        }
    }
    // 如果整个循环完成后仍未读取任何字节,将 b.err 设置为 io.ErrNoProgress。
    b.err = io.ErrNoProgress
}

explicar:

  • fillEl método es Readerun método de la estructura y no tiene un receptor explícito, pero utiliza blos campos de la estructura.
  • Primero, si el puntero de lectura del búfer b.res mayor que cero, significa que hay datos no leídos en el búfer y estos datos se mueven al principio del búfer.
  • Luego, verifique si el búfer está lleno y, de ser así, entre en pánico.
  • Luego, realizando un bucle una cierta cantidad de veces ( maxConsecutiveEmptyReads), intente b.rdleer nuevos bloques de datos de la fuente de lectura en el búfer.
    • Si el número de bytes leídos nes menor que cero, se produce pánico, lo que indica que la lectura devolvió un número negativo.
    • Mueva el puntero de escritura hacia adelante, lo que indica que los bytes b.wse leyeron correctamente .n
    • Si se produce un error, guárdelo b.erry finalice el método.
    • Si al menos un byte se lee correctamente, salga del ciclo.
  • Si todo el ciclo se completa sin que se lea ningún byte, se b.errestablece en io.ErrNoProgress.

efecto:

  • fillLa función principal del método es garantizar que siempre haya datos legibles en el búfer para mejorar la eficiencia de la lectura.
  • Lee nuevos bloques de datos de la fuente de lectura y llena el búfer con datos.
  • Antes de completar los datos, se realizan algunas operaciones, como mover datos no leídos al principio del búfer.

5. Peek: bytes preleídos

// readErr 返回当前的错误并清空错误状态。
func (b *Reader) readErr() error {
    
    
	err := b.err
	b.err = nil
	return err
}

explicar:

  • readErrEl método es Readerun método de la estructura y no tiene un receptor explícito, pero utiliza blos campos de la estructura.
  • Este método devuelve el error actual ( b.err) y borra el estado del error.
  • Almacene el error actual en la variable erry b.errconfigúrelo en nil.
  • Finalmente, se devuelve el error almacenado.

efecto:

  • Este método se utiliza para obtener el error actual y borrar el estado del error para que pueda usarse cuando sea necesario manejar errores.
// Peek 返回下一个 n 个字节而不移动读取器的位置。
// 这些字节在下一次读取调用时不再有效。
// 如果 Peek 返回少于 n 个字节,它还会返回一个解释为为什么读取不完整的错误。
// 如果 n 大于 b 的缓冲区大小,则错误是 [ErrBufferFull]。
//
// 调用 Peek 会阻止 [Reader.UnreadByte] 或 [Reader.UnreadRune] 的调用成功,直到下一次读取操作。
func (b *Reader) Peek(n int) ([]byte, error) {
    
    
	if n < 0 {
    
    
		return nil, ErrNegativeCount
	}

	b.lastByte = -1
	b.lastRuneSize = -1

	// 当缓冲区中剩余数据不足 n 时,且缓冲区未满且没有错误时,调用 fill 方法填充缓冲区。
	for b.w-b.r < n && b.w-b.r < len(b.buf) && b.err == nil {
    
    
		b.fill() // b.w-b.r < len(b.buf) => buffer is not full
	}

	if n > len(b.buf) {
    
    
		return b.buf[b.r:b.w], ErrBufferFull
	}

	// 0 <= n <= len(b.buf)
	var err error
	if avail := b.w - b.r; avail < n {
    
    
		// 缓冲区中的数据不足
		n = avail
		err = b.readErr()
		if err == nil {
    
    
			err = ErrBufferFull
		}
	}
	return b.buf[b.r : b.r+n], err
}

explicar:

  • PeekEl método es Readerun método de la estructura y no tiene un receptor explícito, pero utiliza blos campos de la estructura.
  • Este método devuelve los siguientes nbytes sin mover la posición del lector.
  • Si Peekse devuelven menos de bytes n, también devuelve un error que explica por qué la lectura fue incompleta.
  • Si nes mayor que bel tamaño del buffer de , el error es ErrBufferFull.
  • La llamada Peekevita Reader.UnreadByteque las llamadas Reader.UnreadRunese realicen correctamente hasta la siguiente operación de lectura.

efecto:

  • PeekMétodo de prelectura de bytes, permitiendo visualizar pero no consumir los datos del buffer.
  • Si necesita ver los siguientes bytes sin mover la posición de lectura, puede utilizar Peekel método.

6. Descartar: descartar bytes

// Discard 跳过接下来的 n 个字节,并返回丢弃的字节数。

// 如果 Discard 跳过的字节数少于 n 个,它也会返回一个错误。
// 如果 0 <= n <= b.Buffered(),则 Discard 保证在不从底层 io.Reader 读取的情况下成功执行。
func (b *Reader) Discard(n int) (discarded int, err error) {
    
    
	if n < 0 {
    
    
		return 0, ErrNegativeCount
	}
	if n == 0 {
    
    
		return
	}

	b.lastByte = -1
	b.lastRuneSize = -1

	remain := n
	for {
    
    
		skip := b.Buffered()
		if skip == 0 {
    
    
			b.fill()
			skip = b.Buffered()
		}
		if skip > remain {
    
    
			skip = remain
		}
		b.r += skip
		remain -= skip
		if remain == 0 {
    
    
			return n, nil
		}
		if b.err != nil {
    
    
			return n - remain, b.readErr()
		}
	}
}

explicar:

  • DiscardEl método es Readerun método de la estructura y no tiene un receptor explícito, pero utiliza blos campos de la estructura.
  • Este método omite nlos siguientes bytes y devuelve el número de bytes descartados.
  • También devuelve un error si Discardse omiten menos de bytes .n
  • En 0 <= n <= b.Buffered()el caso de , Discardse garantiza una ejecución exitosa sin necesidad io.Readerde leer desde el subyacente.

efecto:

  • DiscardEl método permite omitir una cantidad específica de bytes sin leerlos ni devolverlos, lo cual es útil para consumir partes de los datos que no se necesitan antes.
  • Ayuda a descartar rápidamente una cantidad específica de bytes sin tener que io.Readerleer esos bytes del archivo .

Supongo que te gusta

Origin blog.csdn.net/weixin_49015143/article/details/135181691
Recomendado
Clasificación