Go-Quellcode-Lernen: bufio package-1.1-bufio.go-(1)

Offizielle Dokumentation des Bufio-Pakets

Gehen Sie zum Quellcode-Learning-Index-Verzeichnis

1. Die Funktion des Bufio-Pakets

bufioDas Paket ist ein Toolkit für gepufferte E/A-Funktionen, die in der Go-Sprachstandardbibliothek bereitgestellt werden. Es wird hauptsächlich zur Pufferunterstützung für E/A-Vorgänge verwendet und kann dazu beitragen, die Leistung und Effizienz von E/A-Vorgängen zu verbessern.

bufioDas Paket bietet eine Reihe leistungsstarker Tools, um das Lesen und Schreiben von Daten effizienter und flexibler zu gestalten und die häufige Belegung von Systemressourcen zu reduzieren. Es eignet sich besonders für die Verarbeitung großer Datenmengen oder E/A-Vorgänge, die eine hohe Leistung erfordern. Betriebsszenario .

Konkret bufiostellt das Paket folgende Funktionen und Funktionen bereit:

  1. Gepuffertes Lesen :

    • bufioDas Paket bietet über den Typ Readereine gepufferte Lesefunktion , die die Anzahl der tatsächlichen Lesevorgänge für die zugrunde liegende Datenquelle (z. B. Dateien, Netzwerkverbindungen usw.) reduzieren und dadurch die Leseleistung verbessern kann.
  2. Gepuffertes Schreiben :

    • Durch Writerden Typ bufiounterstützt das Paket gepufferte Schreibvorgänge, die Daten vorübergehend im Speicher speichern, wodurch die Anzahl der tatsächlichen Schreibvorgänge auf das zugrunde liegende Datenziel reduziert und die Schreibleistung verbessert wird.
  3. Effizientes Byte-Handling :

    • Bietet effiziente Verarbeitungsmethoden für Bytes, z. B. Byte-Lesen und -Schreiben sowie andere bytebasierte Vorgänge, die für die Verarbeitung von Binärdaten sehr nützlich sind.
  4. Zeilenscan :

    • bufio.ScannerType kann Text einfach aufteilen und das Zeilenscannen unterstützen. Benutzer können ihre eigenen Segmentierungsfunktionen definieren, um verschiedene Textformate problemlos zu verarbeiten.
  5. Flexibilität und Leistungsverbesserungen :

    • Durch die Pufferung von Daten im Speicher wird die Anzahl der Systemaufrufe reduziert und dadurch die Effizienz und Leistung von E/A-Vorgängen verbessert.

2.bufio.go

1. Der Zweck und die Grundstruktur des bufio-Pakets

// 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)
}

Die obigen Kommentare erläutern bufioden Zweck und die Grundstruktur des Pakets.

Eine ausführlichere Erklärung:

  • bufioDas Paket implementiert gepufferte E/A-Vorgänge, um die Leistung und Effizienz von E/A-Vorgängen zu verbessern.
  • ReaderEine Struktur ist io.Readereine gepufferte Implementierung eines Objekts. Es enthält einen Puffer , ein bufvom Client bereitgestelltes io.ReaderObjekt rdsowie Felder wie Lese- und Schreiborte und Fehlerinformationen.
  • constEinige Konstanten werden deklariert, z. B. die Standardpuffergröße, die minimale Lesepuffergröße und die maximale Anzahl aufeinanderfolgender Leerlesevorgänge.
  • varEinige Fehlervariablen werden deklariert, um ReaderFehlerbedingungen darzustellen, die während der Verwendung auftreten können.
  • NewReaderSizeDie Funktion gibt einen neuen Readermit einer Puffergröße von mindestens der angegebenen Größe zurück. Wenn das Argument io.Readerbereits ausreichend groß ist Reader, wird das zugrunde liegende Argument zurückgegeben Reader.
  • NewReaderDie Funktion gibt einen neuen Readermit der Standardpuffergröße zurück.

2. Größe: Gibt die Größe des zugrunde liegenden Puffers zurück

Dieser Teil des Codes definiert Sizeeine Methode, die Readerdie Größe des zugrunde liegenden Puffers in einer Struktur in Bytes zurückgibt.

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

erklären:

  • SizeEine Methode ist Readereine Methode einer Struktur, ihr Empfänger ist bund ihr Typ ist Reader.
  • Der Hauptteil der Methode besteht darin, dass sie die Länge des Felds in der Struktur return len(b.buf)zurückgibt , also die Größe des zugrunde liegenden Puffers.bbuf

Wirkung:

  • Der Zweck dieser Methode besteht darin, Readereine Schnittstelle für den externen Zugriff auf die zugrunde liegende Puffergröße der Struktur bereitzustellen.

3. Zurücksetzen: Pufferstatus zurücksetzen und Quelle lesen

Dieser Teil des Codes definiert ResetMethoden, die Readerden Status der Struktur zurücksetzen und den Puffer so umschalten, dass er rvon einer neuen Lesequelle liest.

// 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)
}

erklären:

  • ResetEine Methode ist Readereine Methode einer Struktur, ihr Empfänger ist bund ihr Typ ist Reader.
  • Der Hauptteil der Methode umfasst die folgenden Schlüsselschritte:
    1. Vermeiden Sie eine unendliche Rekursion: Wenn es mit bder neuen Lesequelle übereinstimmt r, kehren Sie direkt zurück, um eine unendliche Rekursion zu vermeiden.
    2. Puffer initialisieren: Wenn bufdas Feld ist nil, initialisieren Sie es mit einem neuen Byte-Slice mit der Standardgröße.
    3. Rufen Sie die Reset-Methode auf: Rufen Sie resetdie Methode auf, um den Status des Puffers, der Lesequelle, des letzten Bytes und der letzten Runengröße zurückzusetzen.
// reset 方法用于具体执行 [Reader] 结构体的重置,将各个字段设置为新的状态。
func (b *Reader) reset(buf []byte, r io.Reader) {
    
    
    *b = Reader{
    
    
        buf:          buf,
        rd:           r,
        lastByte:     -1,
        lastRuneSize: -1,
    }
}

Mit dieser internen resetMethode wird gezielt Readerdas Zurücksetzen der Struktur durchgeführt und jedes Feld auf den neuen Zustand gesetzt.

Wirkung:

  • ResetReaderDie Funktion dieser Methode besteht darin , den Status der Struktur zurückzusetzen, sodass neue Daten erneut gelesen werden können, wenn die Lesequelle gewechselt wird oder zwischengespeicherte Daten verworfen werden müssen .
  • Wenn Resetdie beim Aufruf der Methode übergebene Methode mit rder aktuellen übereinstimmt b, bedeutet dies, dass sie versucht, Readersie auf sich selbst zurückzusetzen, und direkt ohne Operation zurückkehrt.
  • Wenn Readeres sich um einen Nullwert handelt (nicht NewReadermit initialisiert), Resetinitialisiert der Aufruf den internen Puffer auf die Standardgröße.

4. füllen: Füllen Sie den Puffer

Dieser Teil des Codes definiert fillMethoden zum Lesen neuer Datenblöcke im Puffer.

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
}

erklären:

  • fillDie Methode ist Readereine Methode der Struktur und hat keinen expliziten Empfänger, sondern verwendet bdie Felder der Struktur.
  • Erstens: Wenn der Lesezeiger des Puffers b.rgrößer als Null ist, bedeutet dies, dass sich ungelesene Daten im Puffer befinden und diese Daten an den Anfang des Puffers verschoben werden.
  • Überprüfen Sie dann, ob der Puffer voll ist, und lösen Sie in diesem Fall eine Panik aus.
  • Versuchen Sie dann, durch eine bestimmte Anzahl von Schleifen ( maxConsecutiveEmptyReads) b.rdneue Datenblöcke von der Lesequelle in den Puffer zu lesen.
    • Wenn die Anzahl der gelesenen Bytes nkleiner als Null ist, wird eine Panik ausgelöst, die darauf hinweist, dass der Lesevorgang eine negative Zahl zurückgegeben hat.
    • Bewegen Sie den Schreibzeiger nach vorne, um anzuzeigen, dass die Bytes b.werfolgreich gelesen wurden .n
    • Wenn ein Fehler auftritt, speichern Sie den Fehler in b.errund beenden Sie die Methode.
    • Wenn mindestens ein Byte erfolgreich gelesen wurde, verlassen Sie die Schleife.
  • Wenn die gesamte Schleife abgeschlossen wird, ohne dass Bytes gelesen werden, wird b.errauf gesetzt io.ErrNoProgress.

Wirkung:

  • fillDie Hauptfunktion der Methode besteht darin, sicherzustellen, dass immer lesbare Daten im Puffer vorhanden sind, um die Leseeffizienz zu verbessern.
  • Es liest neue Datenblöcke von der Lesequelle und füllt den Puffer mit Daten.
  • Bevor die Daten gefüllt werden, werden einige Vorgänge ausgeführt, z. B. das Verschieben ungelesener Daten an den Anfang des Puffers.

5. Peek: Bytes vorlesen

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

erklären:

  • readErrDie Methode ist Readereine Methode der Struktur und hat keinen expliziten Empfänger, sondern verwendet bdie Felder der Struktur.
  • Diese Methode gibt den aktuellen Fehler zurück ( b.err) und löscht den Fehlerstatus.
  • Speichern Sie den aktuellen Fehler in der Variablen errund b.errsetzen Sie ihn auf nil.
  • Abschließend wird der gespeicherte Fehler zurückgegeben.

Wirkung:

  • Diese Methode wird verwendet, um den aktuellen Fehler abzurufen und den Fehlerstatus zu löschen, sodass sie verwendet werden kann, wenn Fehler behandelt werden müssen.
// 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
}

erklären:

  • PeekDie Methode ist Readereine Methode der Struktur und hat keinen expliziten Empfänger, sondern verwendet bdie Felder der Struktur.
  • Diese Methode gibt die nächsten nBytes zurück, ohne die Position des Lesers zu verschieben.
  • Wenn Peekweniger als Bytes zurückgegeben werden n, wird außerdem ein Fehler zurückgegeben, der erklärt, warum der Lesevorgang unvollständig war.
  • Wenn ngrößer als bdie Puffergröße von ist, liegt der Fehler vor ErrBufferFull.
  • Der Aufruf Peekverhindert, dass Aufrufe bis zum nächsten Lesevorgang erfolgreich sind Reader.UnreadByteoder nicht.Reader.UnreadRune

Wirkung:

  • PeekMethode zum Vorlesen von Bytes, die das Anzeigen, aber nicht das Verbrauchen der Daten im Puffer ermöglicht.
  • Wenn Sie die nächsten Bytes sehen müssen, ohne die Leseposition zu verschieben, können Sie Peekdie Methode verwenden.

6. Verwerfen: Bytes verwerfen

// 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()
		}
	}
}

erklären:

  • DiscardDie Methode ist Readereine Methode der Struktur und hat keinen expliziten Empfänger, sondern verwendet bdie Felder der Struktur.
  • Diese Methode überspringt ndie nächsten Bytes und gibt die Anzahl der verworfenen Bytes zurück.
  • Außerdem wird ein Fehler zurückgegeben , wenn Discardweniger als Bytes übersprungen werden .n
  • Im 0 <= n <= b.Buffered()Falle von ist eine erfolgreiche Ausführung ohne Auslesen des Basiswerts Discardgarantiert .io.Reader

Wirkung:

  • DiscardDie Methode ermöglicht das Überspringen einer bestimmten Anzahl von Bytes, ohne sie zu lesen oder zurückzugeben. Dies ist nützlich, um Teile der Daten zu verbrauchen, die zuvor nicht benötigt werden.
  • Es hilft, eine bestimmte Anzahl von Bytes schnell zu verwerfen, ohne io.Readerdiese Bytes tatsächlich aus der zugrunde liegenden Datei lesen zu müssen.

Guess you like

Origin blog.csdn.net/weixin_49015143/article/details/135181691
Recommended