Golang 標準庫——bufio
bufio
bufio 包實現了有緩衝的 I/O。它包裝一個 io.Reader 或 io.Writer 接口對象,創建另一個也實現了該接口,且同時還提供了緩衝和一些文本 I/O 的幫助函數的對象。
Constants
const (
defaultBufSize = 4096
)
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")
)
會被 Scanner 類型返回的錯誤。
type Reader
type Reader struct {
buf []byte
rd io.Reader // reader provided by the client
r, w int // buf read and write positions
err error
lastByte int // last byte read for UnreadByte; -1 means invalid
lastRuneSize int // size of last rune read for UnreadRune; -1 means invalid
}
Reader 實現了給一個 io.Reader 接口對象附加緩衝。
func NewReader
func NewReader(rd io.Reader) *Reader
NewReader 創建一個具有默認大小緩衝、從 r 讀取的 * Reader。NewReader 相當於 NewReaderSize(rd, 4096)
func NewReaderSize
func NewReaderSize(rd io.Reader, size int) *Reader
NewReaderSize 創建一個具有最少有 size 尺寸的緩衝、從 r 讀取的 Reader。如果參數 r 已經是一個具有足夠大緩衝的 Reader 類型值,會返回 r。
func (*Reader)Reset(r io.Reader)
func (b *Reader) Reset(r io.Reader)
Reset 丟棄緩衝中的數據,清除任何錯誤,將 b 重設爲其下層從 r 讀取數據。
func main() {
s := strings.NewReader("ABCEFG")
str := strings.NewReader("123455")
br := bufio.NewReader(s)
b, _ := br.ReadString('\n')
fmt.Println(b)
br.Reset(str)
b, _ = br.ReadString('\n')
fmt.Println(b)
}
func (*Reader)Bufferd
func (b *Reader) Buffered() int
Buffered 返回緩衝中現有的可讀取的字節數。
func main() {
s := strings.NewReader("abcdefg")
br := bufio.NewReader(s)
fmt.Println(br.Buffered())
br.Peek(1)
fmt.Println(br.Buffered())
}
func (*Reader)Peek
func (b *Reader) Peek(n int) ([]byte, error)
Peek 返回輸入流的下 n 個字節,而不會移動讀取位置。返回的 []byte 只在下一次調用讀取操作前合法。如果 Peek 返回的切片長度比 n 小,它也會返會一個錯誤說明原因。如果 n 比緩衝尺寸還大,返回的錯誤將是 ErrBufferFull。
func main() {
s := strings.NewReader("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
br := bufio.NewReader(s)
b, _ := br.Peek(5)
fmt.Printf("%s\n", b)
b[0] = 'a'
b, _ = br.Peek(5)
fmt.Printf("%s\n", b)
}
func (*Reader)Read
func (b *Reader) Read(p []byte) (n int, err error)
Read 讀取數據寫入 p。本方法返回寫入 p 的字節數。本方法一次調用最多會調用下層 Reader 接口一次 Read 方法,因此返回值 n 可能小於 len(p)。讀取到達結尾時,返回值 n 將爲 0 而 err 將爲 io.EOF。
func main() {
s := strings.NewReader("ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890")
br := bufio.NewReader(s)
p := make([]byte, 10)
n, err := br.Read(p)
fmt.Printf("%-20s %-2v %v\n", p[:n], n, err)
n, err = br.Read(p)
fmt.Printf("%-20s %-2v %v\n", p[:n], n, err)
n, err = br.Read(p)
fmt.Printf("%-20s %-2v %v\n", p[:n], n, err)
n, err = br.Read(p)
fmt.Printf("%-20s %-2v %v\n", p[:n], n, err)
n, err = br.Read(p)
fmt.Printf("%-20s %-2v %v\n", p[:n], n, err)
n, err = br.Read(p)
fmt.Printf("%-20s %-2v %v\n", p[:n], n, err)
}
func (*Reader)ReadByte
func (b *Reader) ReadByte() (c byte, err error)
ReadByte 讀取並返回一個字節。如果沒有可用的數據,會返回錯誤。
func (*Reader)UnreadByte
func (b *Reader) UnreadByte() error
UnreadByte 吐出最近一次讀取操作讀取的最後一個字節。(只能吐出最後一個,多次調用會出問題)
func main() {
s := strings.NewReader("ABCDEFG")
br := bufio.NewReader(s)
c, _ := br.ReadByte()
fmt.Printf("%c\n", c)
c, _ = br.ReadByte()
fmt.Printf("%c\n", c)
br.UnreadByte()
c, _ = br.ReadByte()
fmt.Printf("%c\n", c)
}
func (*Reader)ReadRune
func (b *Reader) ReadRune() (r rune, size int, err error)
ReadRune 讀取一個 utf-8 編碼的 unicode 碼值,返回該碼值、其編碼長度和可能的錯誤。如果 utf-8 編碼非法,讀取位置只移動 1 字節,返回 U+FFFD,返回值 size 爲 1 而 err 爲 nil。如果沒有可用的數據,會返回錯誤。
func (*Reader)UnreadRune
func (b *Reader) UnreadRune() error
UnreadRune 吐出最近一次 ReadRune 調用讀取的 unicode 碼值。如果最近一次讀取不是調用的 ReadRune,會返回錯誤。(從這點看,UnreadRune 比 UnreadByte 嚴格很多)
func main() {
s := strings.NewReader("你好,世界!")
br := bufio.NewReader(s)
c, size, _ := br.ReadRune()
fmt.Printf("%c %v\n", c, size)
c, size, _ = br.ReadRune()
fmt.Printf("%c %v\n", c, size)
br.UnreadRune()
c, size, _ = br.ReadRune()
fmt.Printf("%c %v\n", c, size)
}
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 要麼返回一個非 nil 的 line,要麼返回一個非 nil 的 err,兩個返回值至少一個非 nil。
返回的文本不包含行尾的標誌字節("\r\n" 或 "\n")。如果輸入流結束時沒有行尾標誌字節,方法不會出錯,也不會指出這一情況。在調用 ReadLine 之後調用 UnreadByte 會總是吐出最後一個讀取的字節(很可能是該行的行尾標誌字節),即使該字節不是 ReadLine 返回值的一部分。
func main() {
s := strings.NewReader("ABC\nDEF\r\nGHI\r\nGHI")
br := bufio.NewReader(s)
w, isPrefix, _ := br.ReadLine()
fmt.Printf("%q %v\n", w, isPrefix)
w, isPrefix, _ = br.ReadLine()
fmt.Printf("%q %v\n", w, isPrefix)
w, isPrefix, _ = br.ReadLine()
fmt.Printf("%q %v\n", w, isPrefix)
w, isPrefix, _ = br.ReadLine()
fmt.Printf("%q %v\n", w, isPrefix)
}
func (*Reader)ReadSlice
func (b *Reader) ReadSlice(delim byte) (line []byte, err error)
ReadSlice 讀取直到第一次遇到 delim 字節,返回緩衝裏的包含已讀取的數據和 delim 字節的切片。該返回值只在下一次讀取操作之前合法。如果 ReadSlice 放在在讀取到 delim 之前遇到了錯誤,它會返回在錯誤之前讀取的數據在緩衝中的切片以及該錯誤(一般是 io.EOF)。如果在讀取到 delim 之前緩衝就被寫滿了,ReadSlice 失敗並返回 ErrBufferFull。因爲 ReadSlice 的返回值會被下一次 I/O 操作重寫,調用者應儘量使用 ReadBytes 或 ReadString 替代本法功法。當且僅當 ReadBytes 方法返回的切片不以 delim 結尾時,會返回一個非 nil 的錯誤。
func main() {
s := strings.NewReader("ABC,DEF,GHI,JKL")
br := bufio.NewReader(s)
w, _ := br.ReadSlice(',')
fmt.Printf("%q\n", w)
w, _ = br.ReadSlice(',')
fmt.Printf("%q\n", w)
w, _ = br.ReadSlice(',')
fmt.Printf("%q\n", w)
}
func (*Reader)ReadBytes
func (b *Reader) ReadBytes(delim byte) (line []byte, err error)
ReadBytes 讀取直到第一次遇到 delim 字節,返回一個包含已讀取的數據和 delim 字節的切片。如果 ReadBytes 方法在讀取到 delim 之前遇到了錯誤,它會返回在錯誤之前讀取的數據以及該錯誤(一般是 io.EOF)。當且僅當 ReadBytes 方法返回的切片不以 delim 結尾時,會返回一個非 nil 的錯誤。
func main() {
s := strings.NewReader("ABC DEF GHI JKL")
br := bufio.NewReader(s)
w, _ := br.ReadBytes(' ')
fmt.Printf("%q\n", w)
w, _ = br.ReadBytes(' ')
fmt.Printf("%q\n", w)
w, _ = br.ReadBytes(' ')
fmt.Printf("%q\n", w)
}
func (*Reader)ReadString
func (b *Reader) ReadString(delim byte) (line string, err error)
ReadString 讀取直到第一次遇到 delim 字節,返回一個包含已讀取的數據和 delim 字節的字符串。如果 ReadString 方法在讀取到 delim 之前遇到了錯誤,它會返回在錯誤之前讀取的數據以及該錯誤(一般是 io.EOF)。當且僅當 ReadString 方法返回的切片不以 delim 結尾時,會返回一個非 nil 的錯誤。
func main() {
s := strings.NewReader("ABC DEF GHI JKL")
br := bufio.NewReader(s)
w, _ := br.ReadString(' ')
fmt.Printf("%q\n", w)
w, _ = br.ReadString(' ')
fmt.Printf("%q\n", w)
w, _ = br.ReadString(' ')
fmt.Printf("%q\n", w)
}
func (*Reader)WriteTo
func (b *Reader) WriteTo(w io.Writer) (n int64, err error)
WriteTo 方法實現了 io.WriterTo 接口。
func main() {
s := strings.NewReader("ABCEFGHIJKLMN")
br := bufio.NewReader(s)
b := bytes.NewBuffer(make([]byte, 0))
br.WriteTo(b)
fmt.Printf("%s\n", b)
}
type Writer
type Writer struct {
err error
buf []byte
n int
wr io.Writer
}
Writer 實現了爲 io.Writer 接口對象提供緩衝。如果在向一個 Writer 類型值寫入時遇到了錯誤,該對象將不再接受任何數據,且所有寫操作都會返回該錯誤。在說有數據都寫入後,調用者有義務調用 Flush 方法以保證所有的數據都交給了下層的 io.Writer。
func NewWriter
func NewWriter(w io.Writer) *Writer
NewWriter 創建一個具有默認大小緩衝、寫入 w 的 * Writer。NewWriter 相當於 NewWriterSize(wr, 4096)
func NewWriterSize
func NewWriterSize(w io.Writer, size int) *Writer
NewWriterSize 創建一個具有最少有 size 尺寸的緩衝、寫入 w 的 Writer。如果參數 w 已經是一個具有足夠大緩衝的 Writer 類型值,會返回 w。
func (*Writer)Reset
func (b *Writer) Reset(w io.Writer)
Reset 丟棄緩衝中的數據,清除任何錯誤,將 b 重設爲將其輸出寫入 w。
func main() {
b := bytes.NewBuffer(make([]byte, 0))
bw := bufio.NewWriter(b)
bw.WriteString("123456789")
c := bytes.NewBuffer(make([]byte, 0))
bw.Reset(c)
bw.WriteString("456")
bw.Flush()
fmt.Println(b)
fmt.Println(c)
}
func (*Writer)Bufferd
func (b *Writer) Buffered() int
Buffered 返回緩衝中已使用的字節數。
func (*Writer)Available
func (b *Writer) Available() int
Available 返回緩衝中還有多少字節未使用。
func (*Writer) Write
func (b *Writer) Write(p []byte) (nn int, err error)
Write 將 p 的內容寫入緩衝。返回寫入的字節數。如果返回值 nn <len(p),還會返回一個錯誤說明原因。
func (*Writer) WriteString
func (b *Writer) WriteString(s string) (int, error)
WriteString 寫入一個字符串。返回寫入的字節數。如果返回值 nn <len(s),還會返回一個錯誤說明原因。
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 碼值(的 utf-8 編碼),返回寫入的字節數和可能的錯誤。
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 接口。
func main() {
b := bytes.NewBuffer(make([]byte, 0))
bw := bufio.NewWriter(b)
fmt.Println(bw.Available()) // 4096
fmt.Println(bw.Buffered()) // 0
bw.WriteString("ABCDEFGHIJKLMN")
fmt.Println(bw.Available())
fmt.Println(bw.Buffered())
fmt.Printf("%q\n", b)
bw.Flush()
fmt.Println(bw.Available())
fmt.Println(bw.Buffered())
fmt.Printf("%q\n", b)
}
func main() {
b := bytes.NewBuffer(make([]byte, 0))
bw := bufio.NewWriter(b)
// 寫入緩存
// byte等同於 int8
bw.WriteByte('H')
bw.WriteByte('e')
bw.WriteByte('l')
bw.WriteByte('l')
bw.WriteByte('o')
bw.WriteByte(' ')
// rune等同於int32
bw.WriteRune('世')
bw.WriteRune('界')
bw.WriteRune('!')
// 寫入b
bw.Flush()
fmt.Println(b)
}
func main() {
b := bytes.NewBuffer(make([]byte, 0))
s := strings.NewReader("Hello 世界!")
bw := bufio.NewWriter(b)
bw.ReadFrom(s)
//bw.Flush() //ReadFrom無需使用Flush,其自己已經寫入.
fmt.Println(b) // Hello 世界!
}
type ReadWriter
type ReadWriter struct {
*Reader
*Writer
}
ReadWriter 類型保管了指向 Reader 和 Writer 類型的指針,(因此)實現了 io.ReadWriter 接口。
func NewReadWriter
func NewReadWriter(r *Reader, w *Writer) *ReadWriter
NewReadWriter 申請創建一個新的、將讀寫操作分派給 r 和 w 的 ReadWriter。
func main() {
b := bytes.NewBuffer(make([]byte, 0))
bw := bufio.NewWriter(b)
s := strings.NewReader("123")
br := bufio.NewReader(s)
rw := bufio.NewReadWriter(br, bw)
p, _ := rw.ReadString('\n')
fmt.Println(string(p)) //123
rw.WriteString("asdf")
rw.Flush()
fmt.Println(b) //asdf
}
type SplitFunc
type SplitFunc func(data []byte, atEOF bool) (advance int, token []byte, err error)
SplitFunc 類型代表用於對輸出作詞法分析的分割函數。
參數 data 是尚未處理的數據的一個開始部分的切片,參數 atEOF 表示是否 Reader 接口不能提供更多的數據。返回值是解析位置前進的字節數,將要返回給調用者的 token 切片,以及可能遇到的錯誤。如果數據不足以(保證)生成一個完整的 token,例如需要一整行數據但 data 裏沒有換行符,SplitFunc 可以返回 (0, nil, nil) 來告訴 Scanner 讀取更多的數據寫入切片然後用從同一位置起始、長度更長的切片再試一次(調用 SplitFunc 類型函數)。
如果返回值 err 非 nil,掃描將終止並將該錯誤返回給 Scanner 的調用者。
除非 atEOF 爲真,永遠不會使用空切片 data 調用 SplitFunc 類型函數。然而,如果 atEOF 爲真,data 卻可能是非空的、且包含着未處理的文本。
SplitFunc 的作用很簡單,從 data 中找出你感興趣的數據,然後返回並告訴調用者,data 中有多少數據你已經處理過了
func ScanBytes
func ScanBytes(data []byte, atEOF bool) (advance int, token []byte, err error)
ScanBytes 是用於 Scanner 類型的分割函數(符合 SplitFunc),本函數會將每個字節作爲一個 token 返回。
func ScanRunes
func ScanRunes(data []byte, atEOF bool) (advance int, token []byte, err error)
ScanRunes 是用於 Scanner 類型的分割函數(符合 SplitFunc),本函數會將每個 utf-8 編碼的 unicode 碼值作爲一個 token 返回。本函數返回的 rune 序列和 range 一個字符串的輸出 rune 序列相同。錯誤的 utf-8 編碼會翻譯爲 U+FFFD = "\xef\xbf\xbd",但只會消耗一個字節。調用者無法區分正確編碼的 rune 和錯誤編碼的 rune。
func ScanWords
func ScanWords(data []byte, atEOF bool) (advance int, token []byte, err error)
ScanRunes 是用於 Scanner 類型的分割函數(符合 SplitFunc),本函數會將空白(參見 unicode.IsSpace)分隔的片段(去掉前後空白後)作爲一個 token 返回。本函數永遠不會返回空字符串。用來找出 data 中的單行數據並返回(包括空行)
func ScanLines
func ScanLines(data []byte, atEOF bool) (advance int, token []byte, err error)
ScanLines 是用於 Scanner 類型的分割函數(符合 SplitFunc),本函數會將每一行文本去掉末尾的換行標記作爲一個 token 返回。返回的行可以是空字符串。換行標記爲一個可選的回車後跟一個必選的換行符。最後一行即使沒有換行符也會作爲一個 token 返回。
type Scanner
type Scanner struct {
r io.Reader // The reader provided by the client.
split SplitFunc // The function to split the tokens.
maxTokenSize int // Maximum size of a token; modified by tests.
token []byte // Last token returned by split.
buf []byte // Buffer used as argument to split.
start int // First non-processed byte in buf.
end int // End of data in buf.
err error // Sticky error.
}
Scanner 類型提供了方便的讀取數據的接口,如從換行符分隔的文本里讀取每一行。成功調用的 Scan 方法會逐步提供文件的 token,跳過 token 之間的字節。token 由 SplitFunc 類型的分割函數指定;默認的分割函數會將輸入分割爲多個行,並去掉行尾的換行標誌。本包預定義的分割函數可以將文件分割爲行、字節、unicode 碼值、空白分隔的 word。調用者可以定製自己的分割函數。掃描會在抵達輸入流結尾、遇到的第一個 I/O 錯誤、token 過大不能保存進緩衝時,不可恢復的停止。當掃描停止後,當前讀取位置可能會遠在最後一個獲得的 token 後面。需要更多對錯誤管理的控制或 token 很大,或必須從 reader 連續掃描的程序,應使用 bufio.Reader 代替。
func NewScanner
func NewScanner(r io.Reader) *Scanner
NewScanner 創建並返回一個從 r 讀取數據的 Scanner,默認的分割函數是 ScanLines。
func (*Scanner) Split
func (s *Scanner) Split(split SplitFunc)
Split 設置該 Scanner 的分割函數。本方法必須在 Scan 之前調用。
func main() {
s := strings.NewReader("ABC DEF GHI JKL")
bs := bufio.NewScanner(s)
bs.Split(bufio.ScanWords)
for bs.Scan() {
fmt.Println(bs.Text())
}
}
func (*Scanner) Scan
func (s *Scanner) Scan() bool
Scan 方法獲取當前位置的 token(該 token 可以通過 Bytes 或 Text 方法獲得),並讓 Scanner 的掃描位置移動到下一個 token。當掃描因爲抵達輸入流結尾或者遇到錯誤而停止時,本方法會返回 false。在 Scan 方法返回 false 後,Err 方法將返回掃描時遇到的任何錯誤;除非是 io.EOF,此時 Err 會返回 nil。
func main() {
s := strings.NewReader("Hello 世界!")
bs := bufio.NewScanner(s)
bs.Split(bufio.ScanBytes)
for bs.Scan() {
fmt.Printf("%s ", bs.Text())
}
}
func (*Scanner) Bytes
func (s *Scanner) Bytes() []byte
Bytes 方法返回最近一次 Scan 調用生成的 token。底層數組指向的數據可能會被下一次 Scan 的調用重寫。
func main() {
s := strings.NewReader("Hello 世界!")
bs := bufio.NewScanner(s)
bs.Split(bufio.ScanRunes)
for bs.Scan() {
fmt.Printf("%s ", bs.Text())
}
}
func (*Scanner) Text
func (s *Scanner) Text() string
Bytes 方法返回最近一次 Scan 調用生成的 token,會申請創建一個字符串保存 token 並返回該字符串。
func (*Scanner) Err
func (s *Scanner) Err() error
Err 返回 Scanner 遇到的第一個非 EOF 的錯誤。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://www.jianshu.com/p/bcbf141490c0