Bufio
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.IsSpaceReadWriter
ReadWriter是存储了Reader和Writer指针的结构体,它实现了io.Reader和io.Writer接口type ReadWriter struct {
*Reader
*Writer
}
func NewReadWriter(r *Reader, w *Writer) *ReadWriter
NewReadWriter分配了一个ReadWriter分发给r和wReader
Reader实现了可缓冲的io.Readertype Reader struct {
// contains filtered or unexported fields
}
func NewReader(rd io.Reader) *Reader
返回一个具有默认大小缓冲区新Readerfunc NewReaderSize(rd io.Reader, size int) *Reader
返回缓冲区至少具有指定大小的新Reader,如果rd已经具有足够的大小,那么将会返回底层的Readerfunc (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太大,将会返回ErrBufferFullfunc (b *Reader) Read(p []byte) (n int, err error)
Read读取数据到pfunc (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为1func (*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置换为rfunc (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的WriteToScanner
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,默认分割函数是SplitLinesfunc (*Scanner) Buffer(buf []byte, max int)
Buffer设置初始化的buffer,以及扫描过程中可能分配的最大缓冲区大小,最大的token大小是max和cap(buf)中的最大者,如果max <=cap(buf),扫描过程中将不会分配内存 默认情况下,Buffer使用内部缓冲区,且设置最大token大小为MaxScanTokenSize 扫描已经开始,Buffer可能会panicfunc (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 errorfunc (*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函数,将会panicfunc (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,将输入输出到底层Writertype Writer struct {
// contains filtered or unexported fields
}
func NewWriter(w io.Writer) *Writer
返回一个带有默认buffer的新Writerfunc NewWriterSize(w io.Writer, size int) (*Writer)
返回缓冲区至少为size的Writer,如果底层Writer已经有足够的缓冲区,将会返回底层Writerfunc (b *Writer) Available() int
返回缓冲区未使用的字节数func (b *Writer) Flush() error
刷新数据到底层的Writerfunc (b *Writer) ReadFrom(r io.Reader) (n int64, err error)
实现了io.ReadFrom接口,如果底层实现了io.ReadFrom接口,那么将会使用底层Writer(无论是否有缓冲)func (b *Writer) Reset(w *Writer)
丢弃缓冲中数据,清除错误,将底层Writer设置为wfunc (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写入单个bytefunc (b *Writer) WriteRune(r rune) (size int, err error)
写入rune,返回大小和错误func (b *Writer) WriteString(s string) (int, error)
写入字符串,返回写入的字节,如果写入小于len(s),返回错误解释原因