bufio Overview

bufio实现了带缓冲的io操作,提供了对io.Reader,io.Write封装对象Reader,Writer,不仅实现了这些接口,而且提供了缓冲和一些文本的I/O辅助函数

常量(Constants)


const (
    // 缓冲一个token的最大分配大小
    // 除非用户为Scanner.Buffer提供显式缓冲区
    // 实际上缓冲区的最大大小可能比MaxScanTokenSize小
    // 可能需要包括,比如newline
    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")
)
由Scanner返回的错误
var (
    ErrTooLong = errors.New("")
    ErrNegativeAdvance = errors.New("bufio.Scanner: SplitFunc return negative advance count")
    ErrAdvanceTooFar = errors.New("bufio.Scanner: SplitFunc return advance count beyond input")
)
ErrFinalToken是一个特殊的哨兵错误值,用于指示这应该是Split最后一次传入token,扫描应该停止,ErrFinalToken被Scan接收后,扫描会无错误的返回,这个值对于过早的返回或者必须最后递送一个空token是很有用的,通过自定义error同样也可以实现同样的功能,但是在这提供一个更简洁

Functions

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

ScanBytes是一个Scanner的分割函数,用于将每个byte作为token返回

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

ScanLines是Scanner的一个分割函数,用于返回每一行的文本(剥离行尾标记),行尾标记是一个可选的回车符和一个换行符,最后一个非空文本会被返回,即使没有换行符

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

ScanRunes是Scanner的一个分割函数,用于返回分割的Rune,如果出现Rune编码错误,将会把其返回替换为U+FFFD = "\xef\xbf\xbd",由于Scan接口的原因,如果扫描过程中出现错误,客户端无法区别是由编码错误被替换的,还是正确编码产生的

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

ScanWords是Scanner的一个分割函数,返回由空格分割的文本,它从不返回空字符串,关于空格的定义采用的是unicode.IsSpace

ReadWriter

ReadWriter是存储了Reader和Writer指针的结构体,它实现了io.Reader和io.Writer接口
type ReadWriter struct {
    *Reader
    *Writer
}

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

NewReadWriter分配了一个ReadWriter分发给r和w

Reader

Reader实现了可缓冲的io.Reader
type Reader struct {
    // contains filtered or unexported fields
}

func NewReader(rd io.Reader) *Reader

返回一个具有默认大小缓冲区新Reader

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

返回缓冲区至少具有指定大小的新Reader,如果rd已经具有足够的大小,那么将会返回底层的Reader

func (b *Reader) Buffered() int

返回目前缓冲区可读的字节大小

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

Discard废弃接下来的n个字节,如果 0 <= n <= r.Buffered(),且不读取底层Reader,那么函数将保证成功

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

Peek在不偏移Reader的情况下,返回接下来的n个字节,如果返回少于n个字节,将会返回错误,如果n太大,将会返回ErrBufferFull

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

Read读取数据到p

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

读取并返回一个byte,如果没有byte可提供,将会返回错误

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

ReadBytes读取输入直到第一次出现delim,并返回读取的数据(包括delim),如果读取过程中出现错误(通常是io.EOF),将会返回读取到的数据和错误
package main

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

func main() {
	r := strings.NewReader("hello, bufio readbytes function")
	b := bufio.NewReader(r)
	data, err := b.ReadBytes('s')
	if err != nil {
		panic(err)
	}
	fmt.Println(string(data))
}

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

ReadLine是底层读取一行的原语,大多调用者应该调用ReadBytes('\n'),ReadString("\n")或者使用Scanner ReadLine试图返回一行,不包括结尾的换行符,如果行太长,将会返回行开始且设置isPrefix,剩下的将会在以后返回,最后一次会将isPrefix设为false,buffer只会有效直到下次调用ReadLine,ReadLine返回non-nil line或者 non-nil error,不会同时存在,返回的字节不会包括"\n"或者"\r\n",如果文本结尾没有换行符,不会有错误和指示

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

ReadRune读取一个Rune并返回其size,如果读取的Rune不合理,它消费一个byte并返回unicode.ReplaceChar(U+FFFD)和size为1

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

ReadSlice读取直到第一次出现delim,返回buffer的指针,在下次读取之前都保持有效,如果ReadSlice查找delim中出现错误,它将返回buffer里所有数据和错误(通常是io.EOF),如果buffer已经满了还没找到delim,将会返回ErrBufferFull,因为该函数返回的数据将会在下次调用被重写,大多数用户应该使用ReadBytes或ReadString,ReadSlice返回错误仅当line没有以delim结尾

func (*Reader) ReadString(delim byte) string

ReadString读取数据知道第一次出现delim,数据中包含delim,如果在寻找delim过程中出现错误,将会返回读取到的数据和错误(通常是io.EOF),ReadString返回err != nil当且仅当数据不以delim结尾

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

Reset丢弃缓冲中的数据,并且将底层的Reader置换为r

func (b *Reader) Size() int

返回底层buffer使用的大小

func (b *Reader) UnreadByte() error

unread最近的byte,只有最近读取的byte才能被unread,UnreadByte调用后只能调用read函数才能再次调用,Peek不属于读操作

func (b *Reader) UnreadRune() error

unread最近的rune,只有再次调用ReadRune才能再次被调用,否则发生错误(严格于UnreadByte)

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

实现WriteTo接口,可能会多次调用底层Reader的Read,如果底层Reader实现了WriteTo,将不会利用缓冲直接调用底层Reader的WriteTo

Scanner

Scanner用于提供读取的接口读取数据比如由换行分割的文本,成功的调用Scan逐步浏览'token',跳过标记之间的bytes,明确地的'token'是由type SplitFunc定义,默认的分割函数是由行分割,包中定义的分割函数用于扫描行(line),字节(bytes),UTF-8 encode runes,space-delimited-word,用户可能使用自定义函数代替,扫描停止在EOF,first-error,token对于buffer太大,是不可恢复的,当扫描停止时,底层的Reader可能离上个token任意距离,扫描过程中需要更多处理应该使用bufio.Reader完成
type Scanner struct {
    // contains filtered or unexported fields
}

func NewScanner(r io.Reader) *Scanner

返回一个从r读取的新Scanner,默认分割函数是SplitLines

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

Buffer设置初始化的buffer,以及扫描过程中可能分配的最大缓冲区大小,最大的token大小是max和cap(buf)中的最大者,如果max <=cap(buf),扫描过程中将不会分配内存 默认情况下,Buffer使用内部缓冲区,且设置最大token大小为MaxScanTokenSize 扫描已经开始,Buffer可能会panic

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

Bytes返回最近扫描产生的token,使用内部缓冲区返回
package main
import (
	"fmt"
	"bufio"
	"strings"
)

func main() {
	r := strings.NewReader("hello, i will call you\ncan you fell me?")
	br := bufio.NewScanner(r)
	_ = br.Scan()
	data := br.Bytes()
	fmt.Println(string(data))
}

func (*Scanner) Err() error

返回扫描过程中出现的non-EOF error

func (*Scanner) Scan() bool

Scan推动Scanner到next token,如果扫描停止将会返回false,除了遇到io.EOF错误,其他错误将会在Err方法中返回non-nil错误,Scan将会panic,如果调用返回太多empty token由于Scanner没有前进,这是所有Scanner的共同模式

func (s *Scanner) Split(split SplitFunc)

Split设置扫描过程中的分割函数,默认分割函数是ScanLines 如果在扫描已经开始设置Split函数,将会panic

func (s *Scanner) Text() string

返回最近新分配的string拥有扫描生成的token的bytes
// scanner.go
package main
import (
	"fmt"
	"os"
	"bufio"
)

func main() {
	fileEntry, err := os.Open("scanner.go")
	if err != nil {
		panic(err)
	}
	br := bufio.NewScanner(fileEntry)
	// delim by newline
	lineCount := 0
	for br.Scan() {
		fmt.Println(br.Text())
		lineCount++
	}
	if err := br.Err(); err != nil {
		fmt.Println(err)
	}
	fmt.Printf("file occur %d lines\n", lineCount)
	defer fileEntry.Close()
}

SplitFunc

SplitFunc是标志化输入的分割函数签名,参数是剩余未处理初始字符串和atEOF标志,返回值是next token前进的字节数和可能出现的错误,Scan停止当出现错误,可能会造成数据被丢弃 除非atEOF是true否则永远不会由empty slice调用,如果atEOF是true,则返回的非空数据可能包含未处理的文本
// words count
package main
import (
	"bufio"
	"fmt"
	"strings"
	"os"
)

func main() {
	text := "int int32 int64 uint uint32 uint64 float32 float64 ..."
	r := strings.NewReader(text)
	br := bufio.NewScanner(r)
	br.Split(bufio.ScanWords)
	wordCount := 0
	for br.Scan() {
		wordCount++
	}
	if err := br.Err(); err != nil {
		fmt.Fprintf(os.Stderr, "scan error: %s\n", err)
	}
	fmt.Printf("word occur count: %d\n", wordCount)
}

Custom Split Func

package main
import (
	"bufio"
	"strings"
	"fmt"
	"strconv"
	"os"
)
// 自定义分割函数,用于检查输入是否是合理的32bit数字
func main() {
	text := "123 456 7869 12345679012901290"
	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
	}
	br := bufio.NewScanner(strings.NewReader(text))
	br.Split(split)
	for br.Scan() {
		fmt.Println(br.Text())
	}
	if err := br.Err(); err != nil {
		fmt.Fprintf(os.Stderr, "error: %s\n", err)
	}
}

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

func main() {
	br := bufio.NewScanner(strings.NewReader("1,2,3,4"))
	split := 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
			}
		}
		// !atEOF 不读完
		if !atEOF {
			return 0, nil, nil
		}
		// atEOF 读完 but not end in ','
		return 0, data, bufio.ErrFinalToken
	}
	br.Split(split)
	for br.Scan() {
		fmt.Println(br.Text())
	}
	if err := br.Err(); err != nil {
		fmt.Fprintf(os.Stderr, "error: %s\n", err)
	}
}

Writer

Writer为io.Writer对象实现了缓冲,如果写入Writer发生错误,没有数据将会被接收,后续写入,Flush,将会返回错误,在所有数据写入之后,调用者确保调用Flush,将输入输出到底层Writer
type Writer struct {
    // contains filtered or unexported fields
}

func NewWriter(w io.Writer) *Writer

返回一个带有默认buffer的新Writer

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

返回缓冲区至少为size的Writer,如果底层Writer已经有足够的缓冲区,将会返回底层Writer

func (b *Writer) Available() int

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

func (b *Writer) Flush() error

刷新数据到底层的Writer

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

实现了io.ReadFrom接口,如果底层实现了io.ReadFrom接口,那么将会使用底层Writer(无论是否有缓冲)

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

丢弃缓冲中数据,清除错误,将底层Writer设置为w

func (b *Writer) Size() int

返回底层buffer使用的大小

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

将会p中数据写入buffer,如果n < len(p),会返回错误解释写入较短的原因

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

WriteByte写入单个byte

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

写入rune,返回大小和错误

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

写入字符串,返回写入的字节,如果写入小于len(s),返回错误解释原因