package bufio

import "bufio"

bufio 包实现了带缓冲的 I/O 操作。它封装了 io.Reader 或 io.Writer 对象,创建出同样实现对应接口的 Reader 或 Writer 对象, 并提供缓冲功能与文本 I/O 的辅助支持。

Index

Examples

Constants

const (
	// MaxScanTokenSize 是缓冲标记的最大大小,除非用户通过 Scanner.Buffer 显式提供缓冲区。
	// 实际最大标记大小可能更小,因为缓冲区可能需要包含换行符等内容。
	MaxScanTokenSize = 64 * 1024
)

Variables

var (
	ErrInvalidUnreadByte = errors.New("bufio: invalid use of UnreadByte")
	ErrInvalidUnreadRune = errors.New("bufio: invalid use of UnreadRune")
	ErrBufferFull        = errors.New("bufio: buffer full")
	ErrNegativeCount     = errors.New("bufio: negative count")
)
var (
	ErrTooLong         = errors.New("bufio.Scanner: token too long")
	ErrNegativeAdvance = errors.New("bufio.Scanner: SplitFunc returns negative advance count")
	ErrAdvanceTooFar   = errors.New("bufio.Scanner: SplitFunc returns advance count beyond input")
	ErrBadReadCount    = errors.New("bufio.Scanner: Read returned impossible count")
)

Scanner 返回的错误

var ErrFinalToken = errors.New("final token")

ErrFinalToken 是一个特殊的标记错误值。 它旨在由分割函数返回,指示扫描应无错误停止。 若随此错误传递的标记非 nil,该标记即为最后一个标记。

该值用于提前停止处理,或在需要传递最终空标记(与 nil 标记不同)时使用。 可以用自定义错误值实现相同行为,但在此提供一个更整洁。 参见 emptyFinalToken 示例了解该值的用法。

Functions

func ScanBytes

func ScanBytes(data []byte, atEOF bool) (advance int, token []byte, err error)

ScanBytes 是 Scanner 的分割函数,将每个字节作为一个标记返回。

func ScanLines

func ScanLines(data []byte, atEOF bool) (advance int, token []byte, err error)

ScanLines 是 Scanner 的分割函数,将每行文本作为标记返回,并去除任何尾随的行尾标记。 返回的行可能为空。行尾标记是一个可选的回车符后跟一个强制的换行符。 在正则表达式表示法中,它是 `\r?\n`。 输入的最后一个非空行即使没有换行符也会被返回。

func ScanRunes

func ScanRunes(data []byte, atEOF bool) (advance int, token []byte, err error)

ScanRunes 是 Scanner 的分割函数,将每个 UTF-8 编码的字符作为一个标记返回。 返回的字符序列与对输入作为字符串进行 range 循环的结果等效, 这意味着错误的 UTF-8 编码会转换为 U+FFFD = "\xef\xbf\xbd"。 由于 Scan 接口,客户端无法区分正确编码的替换字符与编码错误。

func ScanWords

func ScanWords(data []byte, atEOF bool) (advance int, token []byte, err error)

ScanWords 是 Scanner 的分割函数,将每个空格分隔的单词作为标记返回,并去除周围的空格。 它永远不会返回空字符串。空格的定义由 unicode.IsSpace 设定。

Types

type ReadWriter

type ReadWriter struct {
	*Reader
	*Writer
}

ReadWriter 存储 Reader 与 Writer 的指针, 实现 io.ReadWriter 接口。

func NewReadWriter

func NewReadWriter(r *Reader, w *Writer) *ReadWriter

NewReadWriter 分配一个新的 ReadWriter,读写操作分别转发至 r 和 w。

type Reader

type Reader struct {
	// contains filtered or unexported fields
}

Reader 为 io.Reader 对象实现缓冲读取功能。 可通过调用 NewReader 或 NewReaderSize 创建新的 Reader; 此外,Reader 的零值可在调用 Reset 方法后使用。

func NewReader

func NewReader(rd io.Reader) *Reader

NewReader 返回缓冲区使用默认大小的新 Reader。

func NewReaderSize

func NewReaderSize(rd io.Reader, size int) *Reader

NewReaderSize 返回一个缓冲区容量至少为指定大小的新 Reader。 若传入的 io.Reader 本身已是容量足够的 Reader,则直接返回该底层 Reader。

func (*Reader) Buffered

func (b *Reader) Buffered() int

Buffered 返回当前缓冲区中可读取的字节数。

func (*Reader) Discard

func (b *Reader) Discard(n int) (discarded int, err error)

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

若 Discard 跳过的字节数少于 n,会同时返回错误。 若 0 <= n <= 缓冲数据量,Discard 保证无需读取底层 io.Reader 即可成功执行。

func (*Reader) Peek

func (b *Reader) Peek(n int) ([]byte, error)

Peek 返回接下来的 n 个字节,且不移动读取指针。 这些字节在下一次读取操作后将失效。 必要时,Peek 会向缓冲区读取更多数据以满足 n 个字节的需求。 若 Peek 返回的字节数少于 n,会同时返回解释读取不足原因的错误。 若 n 大于缓冲区容量,错误为 ErrBufferFull。

调用 Peek 后,在下次读取操作前,UnreadByte 或 UnreadRune 调用会失败。

func (*Reader) Read

func (b *Reader) Read(p []byte) (n int, err error)

Read 将数据读取至 p 中。 返回读取到 p 中的字节数。 数据最多仅调用一次底层 Reader 的 Read 方法获取, 因此 n 可能小于 len(p)。 若需精确读取 len(p) 个字节,使用 io.ReadFull(b, p)。 若底层 Reader 可在返回 io.EOF 时同时返回非零字节数, 本 Read 方法也会遵循该行为;详见 io.Reader 文档。

func (*Reader) ReadByte

func (b *Reader) ReadByte() (byte, error)

ReadByte 读取并返回单个字节。 若无可用字节,返回错误。

func (*Reader) ReadBytes

func (b *Reader) ReadBytes(delim byte) ([]byte, error)

ReadBytes 读取数据直至输入中首次出现分隔符 delim, 返回包含截止到分隔符(含)所有数据的切片。 若 ReadBytes 在找到分隔符前遇到错误, 会返回错误前已读取的数据与该错误(通常为 io.EOF)。 当且仅当返回的数据未以分隔符结尾时,ReadBytes 返回的 err 不为 nil。 简单场景下,使用 Scanner 会更便捷。

func (*Reader) ReadLine

func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error)

ReadLine 是底层的行读取原语。大多数调用者应优先使用 ReadBytes('\n')、ReadString('\n') 或 Scanner。

ReadLine 尝试返回单行数据,不包含行尾字节。 若行长度超出缓冲区容量,isPrefix 会被设为 true,仅返回行的开头部分, 剩余内容会在后续调用中返回。当返回行的最后片段时,isPrefix 为 false。 返回的缓冲区仅在下一次 ReadLine 调用前有效。 ReadLine 要么返回非空行数据,要么返回错误,二者不会同时返回。

ReadLine 返回的文本不包含行尾符("\r\n" 或 "\n")。 若输入末尾无最终行尾符,不会返回任何提示或错误。 ReadLine 后调用 UnreadByte 总会撤销最后读取的字节 (可能是行尾符),即使该字节不属于 ReadLine 返回的行数据。

func (*Reader) ReadRune

func (b *Reader) ReadRune() (r rune, size int, err error)

ReadRune 读取单个 UTF-8 编码的 Unicode 字符, 返回该字符及其占用的字节数。 若编码字符无效,会消耗 1 个字节并返回 unicode.ReplacementChar (U+FFFD),大小为 1。

func (*Reader) ReadSlice

func (b *Reader) ReadSlice(delim byte) (line []byte, err error)

ReadSlice 读取数据直至输入中首次出现分隔符 delim, 返回指向缓冲区中字节的切片。 该切片数据在下一次读取操作后失效。 若 ReadSlice 在找到分隔符前遇到错误, 会返回缓冲区中所有数据与该错误(通常为 io.EOF)。 若缓冲区填满仍未找到分隔符,ReadSlice 会返回 ErrBufferFull 错误。 由于 ReadSlice 返回的数据会被下一次 I/O 操作覆盖, 大多数客户端应优先使用 ReadBytes 或 ReadString。 当且仅当返回的数据未以分隔符结尾时,ReadSlice 返回的 err 不为 nil。

func (*Reader) ReadString

func (b *Reader) ReadString(delim byte) (string, error)

ReadString 读取数据直至输入中首次出现分隔符 delim, 返回包含截止到分隔符(含)所有数据的字符串。 若 ReadString 在找到分隔符前遇到错误, 会返回错误前已读取的数据与该错误(通常为 io.EOF)。 当且仅当返回的数据未以分隔符结尾时,ReadString 返回的 err 不为 nil。 简单场景下,使用 Scanner 会更便捷。

func (*Reader) Reset

func (b *Reader) Reset(r io.Reader)

Reset 丢弃所有缓冲数据,重置所有状态,并将缓冲读取器切换为从 r 读取数据。 对 Reader 零值调用 Reset 会将内部缓冲区初始化为默认大小。 调用 b.Reset(b)(即重置 Reader 为自身)不会执行任何操作。

func (*Reader) Size

func (b *Reader) Size() int

Size 返回底层缓冲区的字节容量。

func (*Reader) UnreadByte

func (b *Reader) UnreadByte() error

UnreadByte 撤销上一次读取的字节,仅可撤销最近一次读取的字节。

若 Reader 上一次调用的方法不是读取操作,UnreadByte 会返回错误。 特别说明:Peek、Discard 和 WriteTo 不被视为读取操作。

func (*Reader) UnreadRune

func (b *Reader) UnreadRune() error

UnreadRune 撤销上一次读取的字符。 若 Reader 上一次调用的方法不是 ReadRune,UnreadRune 会返回错误。 (在这一点上它比 UnreadByte 更严格,UnreadByte 可撤销任意读取操作的最后字节)

func (*Reader) WriteTo

func (b *Reader) WriteTo(w io.Writer) (n int64, err error)

WriteTo 实现 io.WriterTo 接口。 该方法可能多次调用底层 Reader 的 Read 方法。 若底层读取器支持 WriteTo 方法, 本方法会直接调用底层 WriteTo,不使用缓冲。

type Scanner

type Scanner struct {
	// contains filtered or unexported fields
}

Scanner 提供便捷接口读取数据,例如换行分隔的文本文件。 连续调用 Scanner.Scan 方法会步进文件的“标记”,跳过标记之间的字节。 标记的定义由 SplitFunc 类型的分割函数决定;默认分割函数将输入拆分为行,并去除行尾符。 本包定义了 Scanner.Split 函数,用于将文件扫描为行、字节、UTF-8 编码的字符和空格分隔的单词。 客户端也可提供自定义分割函数。

扫描在遇到 EOF、首个 I/O 错误或标记过大无法放入 Scanner.Buffer 时不可恢复地停止。 扫描停止时,读取器可能已远超最后一个标记。 需要更精细控制错误处理、大标记,或必须在读取器上连续扫描的程序,应改用 bufio.Reader。

Example (Custom)

Use a Scanner with a custom split function (built by wrapping ScanWords) to validate 32-bit decimal input.

package main

import (
	"bufio"
	"fmt"
	"strconv"
	"strings"
)

func main() {
	// An artificial input source.
	const input = "1234 5678 1234567901234567890"
	scanner := bufio.NewScanner(strings.NewReader(input))
	// Create a custom split function by wrapping the existing ScanWords function.
	split := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
		advance, token, err = bufio.ScanWords(data, atEOF)
		if err == nil && token != nil {
			_, err = strconv.ParseInt(string(token), 10, 32)
		}
		return
	}
	// Set the split function for the scanning operation.
	scanner.Split(split)
	// Validate the input
	for scanner.Scan() {
		fmt.Printf("%s\n", scanner.Text())
	}

	if err := scanner.Err(); err != nil {
		fmt.Printf("Invalid input: %s", err)
	}
}

Output:

1234
5678
Invalid input: strconv.ParseInt: parsing "1234567901234567890": value out of range
Example (EarlyStop)

Use a Scanner with a custom split function to parse a comma-separated list with an empty final value but stops at the token "STOP".

package main

import (
	"bufio"
	"bytes"
	"fmt"
	"os"
	"strings"
)

func main() {
	onComma := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
		i := bytes.IndexByte(data, ',')
		if i == -1 {
			if !atEOF {
				return 0, nil, nil
			}
			// If we have reached the end, return the last token.
			return 0, data, bufio.ErrFinalToken
		}
		// If the token is "STOP", stop the scanning and ignore the rest.
		if string(data[:i]) == "STOP" {
			return i + 1, nil, bufio.ErrFinalToken
		}
		// Otherwise, return the token before the comma.
		return i + 1, data[:i], nil
	}
	const input = "1,2,STOP,4,"
	scanner := bufio.NewScanner(strings.NewReader(input))
	scanner.Split(onComma)
	for scanner.Scan() {
		fmt.Printf("Got a token %q\n", scanner.Text())
	}
	if err := scanner.Err(); err != nil {
		fmt.Fprintln(os.Stderr, "reading input:", err)
	}
}

Output:

Got a token "1"
Got a token "2"
Example (EmptyFinalToken)

Use a Scanner with a custom split function to parse a comma-separated list with an empty final value.

package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"
)

func main() {
	// Comma-separated list; last entry is empty.
	const input = "1,2,3,4,"
	scanner := bufio.NewScanner(strings.NewReader(input))
	// Define a split function that separates on commas.
	onComma := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
		for i := 0; i < len(data); i++ {
			if data[i] == ',' {
				return i + 1, data[:i], nil
			}
		}
		if !atEOF {
			return 0, nil, nil
		}
		// There is one final token to be delivered, which may be the empty string.
		// Returning bufio.ErrFinalToken here tells Scan there are no more tokens after this
		// but does not trigger an error to be returned from Scan itself.
		return 0, data, bufio.ErrFinalToken
	}
	scanner.Split(onComma)
	// Scan.
	for scanner.Scan() {
		fmt.Printf("%q ", scanner.Text())
	}
	if err := scanner.Err(); err != nil {
		fmt.Fprintln(os.Stderr, "reading input:", err)
	}
}

Output:

"1" "2" "3" "4" ""
Example (Lines)

The simplest use of a Scanner, to read standard input as a set of lines.

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	for scanner.Scan() {
		fmt.Println(scanner.Text()) // Println will add back the final '\n'
	}
	if err := scanner.Err(); err != nil {
		fmt.Fprintln(os.Stderr, "reading standard input:", err)
	}
}
Example (Words)

Use a Scanner to implement a simple word-count utility by scanning the input as a sequence of space-delimited tokens.

package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"
)

func main() {
	// An artificial input source.
	const input = "Now is the winter of our discontent,\nMade glorious summer by this sun of York.\n"
	scanner := bufio.NewScanner(strings.NewReader(input))
	// Set the split function for the scanning operation.
	scanner.Split(bufio.ScanWords)
	// Count the words.
	count := 0
	for scanner.Scan() {
		count++
	}
	if err := scanner.Err(); err != nil {
		fmt.Fprintln(os.Stderr, "reading input:", err)
	}
	fmt.Printf("%d\n", count)
}

Output:

15

func NewScanner

func NewScanner(r io.Reader) *Scanner

NewScanner 返回一个从 r 读取的新 Scanner。 分割函数默认为 ScanLines。

func (*Scanner) Buffer

func (s *Scanner) Buffer(buf []byte, max int)

Buffer 控制 Scanner 的内存分配。 它设置扫描时使用的初始缓冲区,以及扫描期间可分配的最大缓冲区大小。 缓冲区的内容被忽略。

最大标记大小必须小于 max 和 cap(buf) 中的较大者。 若 max <= cap(buf),Scanner.Scan 将仅使用此缓冲区,不进行内存分配。

默认情况下,Scanner.Scan 使用内部缓冲区,并将最大标记大小设为 MaxScanTokenSize。

若在扫描开始后调用 Buffer,会 panic。

func (*Scanner) Bytes

func (s *Scanner) Bytes() []byte

Bytes 返回 Scanner.Scan 调用生成的最新标记。 底层数组可能指向会被后续 Scan 调用覆盖的数据。不进行内存分配。

Example

Return the most recent call to Scan as a []byte.

package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"
)

func main() {
	scanner := bufio.NewScanner(strings.NewReader("gopher"))
	for scanner.Scan() {
		fmt.Println(len(scanner.Bytes()) == 6)
	}
	if err := scanner.Err(); err != nil {
		fmt.Fprintln(os.Stderr, "shouldn't see an error scanning a string")
	}
}

Output:

true

func (*Scanner) Err

func (s *Scanner) Err() error

Err 返回 Scanner 遇到的首个非 EOF 错误。

func (*Scanner) Scan

func (s *Scanner) Scan() bool

Scan 将 Scanner 前进到下一个标记,该标记随后可通过 Scanner.Bytes 或 Scanner.Text 方法获取。 当无更多标记时(因到达输入末尾或错误)返回 false。 Scan 返回 false 后,Scanner.Err 方法将返回扫描期间发生的任何错误, 但若为 io.EOF,Scanner.Err 将返回 nil。 若分割函数在未前进输入的情况下返回过多空标记,Scan 会 panic。 这是扫描器的常见错误模式。

func (*Scanner) Split

func (s *Scanner) Split(split SplitFunc)

Split 设置 Scanner 的分割函数。 默认分割函数为 ScanLines。

若在扫描开始后调用 Split,会 panic。

func (*Scanner) Text

func (s *Scanner) Text() string

Text 将 Scanner.Scan 调用生成的最新标记作为新分配的字符串返回。

type SplitFunc

type SplitFunc func(data []byte, atEOF bool) (advance int, token []byte, err error)

SplitFunc 是用于将输入标记化的分割函数的签名。 参数为剩余未处理数据的初始子串,以及 atEOF 标志(报告 Reader 是否无更多数据可提供)。 返回值为输入前进的字节数、返回给用户的下一个标记(若有),以及错误(若有)。

若函数返回错误,扫描停止,此时部分输入可能被丢弃。 若错误为 ErrFinalToken,扫描无错误停止。 随 ErrFinalToken 传递的非 nil 标记将是最后一个标记, 随 ErrFinalToken 传递的 nil 标记会立即停止扫描。

否则,Scanner 前进输入。若标记非 nil,Scanner 将其返回给用户。 若标记为 nil,Scanner 读取更多数据并继续扫描;若无更多数据(atEOF 为 true),Scanner 返回。 若数据尚未包含完整标记(例如扫描行时无换行符),SplitFunc 可返回 (0, nil, nil), 示意 Scanner 读取更多数据到切片,并从输入的同一点开始用更长的切片重试。

除非 atEOF 为 true,否则函数永远不会用空数据切片调用。 但若 atEOF 为 true,data 可能非空,且始终包含未处理文本。

type Writer

type Writer struct {
	// contains filtered or unexported fields
}

Writer 为 io.Writer 对象实现缓冲写入功能。 若写入 Writer 时发生错误,将不再接收任何数据, 所有后续写入操作与 Flush 操作都会返回该错误。 所有数据写入完成后,客户端应调用 Flush 方法, 确保所有数据都已提交至底层 io.Writer。

Example
package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	w := bufio.NewWriter(os.Stdout)
	fmt.Fprint(w, "Hello, ")
	fmt.Fprint(w, "world!")
	w.Flush() // Don't forget to flush!
}

Output:

Hello, world!

func NewWriter

func NewWriter(w io.Writer) *Writer

NewWriter 返回缓冲区使用默认大小的新 Writer。 若传入的 io.Writer 本身已是缓冲区足够大的 Writer, 则直接返回该底层 Writer。

func NewWriterSize

func NewWriterSize(w io.Writer, size int) *Writer

NewWriterSize 返回一个缓冲区容量至少为指定大小的新 Writer。 若传入的 io.Writer 本身已是容量足够的 Writer,则直接返回该底层 Writer。

func (*Writer) Available

func (b *Writer) Available() int

Available 返回缓冲区中未使用的字节数。

func (*Writer) AvailableBuffer

func (b *Writer) AvailableBuffer() []byte

AvailableBuffer 返回一个容量为 b.Available() 的空缓冲区。 该缓冲区用于追加数据,并传入紧随其后的 Write 调用。 缓冲区仅在 b 下一次写入操作前有效。

Example
package main

import (
	"bufio"
	"os"
	"strconv"
)

func main() {
	w := bufio.NewWriter(os.Stdout)
	for _, i := range []int64{1, 2, 3, 4} {
		b := w.AvailableBuffer()
		b = strconv.AppendInt(b, i, 10)
		b = append(b, ' ')
		w.Write(b)
	}
	w.Flush()
}

Output:

1 2 3 4

func (*Writer) Buffered

func (b *Writer) Buffered() int

Buffered 返回当前缓冲区中已写入的字节数。

func (*Writer) Flush

func (b *Writer) Flush() error

Flush 将所有缓冲数据写入底层 io.Writer。

func (*Writer) ReadFrom

func (b *Writer) ReadFrom(r io.Reader) (n int64, err error)

ReadFrom 实现 io.ReaderFrom 接口。若底层写入器支持 ReadFrom 方法, 本方法会直接调用底层 ReadFrom。 若存在缓冲数据且底层支持 ReadFrom,本方法会先填满缓冲区并写入, 再调用 ReadFrom。

Example

ExampleWriter_ReadFrom demonstrates how to use the ReadFrom method of Writer.

package main

import (
	"bufio"
	"bytes"
	"fmt"
	"strings"
)

func main() {
	var buf bytes.Buffer
	writer := bufio.NewWriter(&buf)

	data := "Hello, world!\nThis is a ReadFrom example."
	reader := strings.NewReader(data)

	n, err := writer.ReadFrom(reader)
	if err != nil {
		fmt.Println("ReadFrom Error:", err)
		return
	}

	if err = writer.Flush(); err != nil {
		fmt.Println("Flush Error:", err)
		return
	}

	fmt.Println("Bytes written:", n)
	fmt.Println("Buffer contents:", buf.String())
}

Output:

Bytes written: 41
Buffer contents: Hello, world!
This is a ReadFrom example.

func (*Writer) Reset

func (b *Writer) Reset(w io.Writer)

Reset 丢弃所有未刷新的缓冲数据,清除所有错误, 并重置 Writer 以向 w 写入数据。 对 Writer 零值调用 Reset 会将内部缓冲区初始化为默认大小。 调用 w.Reset(w)(即重置 Writer 为自身)不会执行任何操作。

func (*Writer) Size

func (b *Writer) Size() int

Size 返回底层缓冲区的字节容量。

func (*Writer) Write

func (b *Writer) Write(p []byte) (nn int, err error)

Write 将 p 中的内容写入缓冲区。 返回写入的字节数。 若 nn < len(p),会同时返回解释写入不足原因的错误。

func (*Writer) WriteByte

func (b *Writer) WriteByte(c byte) error

WriteByte 写入单个字节。

func (*Writer) WriteRune

func (b *Writer) WriteRune(r rune) (size int, err error)

WriteRune 写入单个 Unicode 码点, 返回写入的字节数与可能发生的错误。

func (*Writer) WriteString

func (b *Writer) WriteString(s string) (int, error)

WriteString 写入字符串。 返回写入的字节数。 若写入字节数小于 len(s),会同时返回解释写入不足原因的错误。