documentación oficial del paquete bufio
Ir al directorio de índice de aprendizaje del código fuente
1. La función del paquete bufio.
bufio
El 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.
bufio
El 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, bufio
el paquete proporciona las siguientes funciones y funciones:
-
Lectura tamponada :
bufio
Reader
El 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.
-
Escritura almacenada en búfer :
- A través
Writer
del tipo,bufio
el 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.
- A través
-
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.
-
Escaneo de líneas :
bufio.Scanner
El 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.
-
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 bufio
el propósito y la estructura básica del paquete.
Una explicación más detallada:
bufio
El paquete implementa operaciones de E/S almacenadas en búfer para mejorar el rendimiento y la eficiencia de las operaciones de E/S.Reader
Una estructura esio.Reader
una implementación almacenada en búfer de un objeto. Contiene un búfer , un objetobuf
proporcionado por el cliente y campos como ubicaciones de lectura y escritura e información de error.io.Reader
rd
const
Se 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.var
Algunas variables de error se declaran para representarReader
condiciones de error que pueden ocurrir durante el uso.NewReaderSize
La función devuelve uno nuevoReader
con un tamaño de búfer de al menos el tamaño especificado. Si el argumentoio.Reader
ya tiene un tamaño suficientemente grandeReader
, se devuelve el subyacenteReader
.NewReader
La función devuelve uno nuevoReader
con el tamaño de búfer predeterminado.
2. Tamaño: devuelve el tamaño del búfer subyacente.
Esta parte del código define Size
un método que devuelve Reader
el tamaño del búfer subyacente en una estructura, en bytes.
// Size 返回底层缓冲区的大小(以字节为单位)。
func (b *Reader) Size() int {
return len(b.buf) }
explicar:
Size
Un método esReader
un método de una estructura, su receptor esb
y su tipo esReader
.- El cuerpo del método es que
return len(b.buf)
devuelve la longitud del campob
en la estructurabuf
, que es el tamaño del búfer subyacente.
efecto:
- El propósito de este método es proporcionar
Reader
una 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 Reset
métodos que restablecen Reader
el estado de la estructura y cambian el búfer para r
leer 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:
Reset
Un método esReader
un método de una estructura, su receptor esb
y su tipo esReader
.- El cuerpo principal del método incluye los siguientes pasos clave:
- Evite la recursividad infinita: si es la misma que
b
la nueva fuente de lecturar
, regrese directamente para evitar la recursividad infinita. - Inicializar búfer: si
buf
el campo esnil
, inicialícelo en un nuevo segmento de bytes con el tamaño predeterminado. - Llame al método de reinicio: llame
reset
al método para restablecer el estado del búfer, la fuente de lectura, el último byte y el tamaño de la última runa.
- Evite la recursividad infinita: si es la misma que
// reset 方法用于具体执行 [Reader] 结构体的重置,将各个字段设置为新的状态。
func (b *Reader) reset(buf []byte, r io.Reader) {
*b = Reader{
buf: buf,
rd: r,
lastByte: -1,
lastRuneSize: -1,
}
}
Este reset
método interno se utiliza para realizar específicamente Reader
el restablecimiento de la estructura y establecer cada campo en el nuevo estado.
efecto:
Reset
Reader
La 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
Reset
lo pasado cuando se llama al método es el mismo quer
el actualb
, significa que está intentando restablecerloReader
a sí mismo y regresará directamente sin ninguna operación. - Cuando
Reader
es un valor cero (noNewReader
inicializado con), la llamadaReset
inicializa el búfer interno al tamaño predeterminado.
4. llenar: llenar el búfer
Esta parte del código define fill
mé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:
fill
El método esReader
un método de la estructura y no tiene un receptor explícito, pero utilizab
los campos de la estructura.- Primero, si el puntero de lectura del búfer
b.r
es 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
), intenteb.rd
leer nuevos bloques de datos de la fuente de lectura en el búfer.- Si el número de bytes leídos
n
es 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.w
se leyeron correctamente .n
- Si se produce un error, guárdelo
b.err
y finalice el método. - Si al menos un byte se lee correctamente, salga del ciclo.
- Si el número de bytes leídos
- Si todo el ciclo se completa sin que se lea ningún byte, se
b.err
establece enio.ErrNoProgress
.
efecto:
fill
La 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:
readErr
El método esReader
un método de la estructura y no tiene un receptor explícito, pero utilizab
los 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
err
yb.err
configúrelo ennil
. - 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:
Peek
El método esReader
un método de la estructura y no tiene un receptor explícito, pero utilizab
los campos de la estructura.- Este método devuelve los siguientes
n
bytes sin mover la posición del lector. - Si
Peek
se devuelven menos de bytesn
, también devuelve un error que explica por qué la lectura fue incompleta. - Si
n
es mayor queb
el tamaño del buffer de , el error esErrBufferFull
. - La llamada
Peek
evitaReader.UnreadByte
que las llamadasReader.UnreadRune
se realicen correctamente hasta la siguiente operación de lectura.
efecto:
Peek
Mé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
Peek
el 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:
Discard
El método esReader
un método de la estructura y no tiene un receptor explícito, pero utilizab
los campos de la estructura.- Este método omite
n
los siguientes bytes y devuelve el número de bytes descartados. - También devuelve un error si
Discard
se omiten menos de bytes .n
- En
0 <= n <= b.Buffered()
el caso de ,Discard
se garantiza una ejecución exitosa sin necesidadio.Reader
de leer desde el subyacente.
efecto:
Discard
El 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.Reader
leer esos bytes del archivo .