1. bufio.Reader
type Reader struct { ... }
// NewReaderSize 將 rd 封裝成一個帶緩存的 bufio.Reader 對象完丽,
// 緩存大小由 size 指定(如果小于 16 則會被設置為 16)拇舀。
// 如果 rd 的基類型就是有足夠緩存的 bufio.Reader 類型,則直接將
// rd 轉(zhuǎn)換為基類型返回聘鳞。
func NewReaderSize(rd io.Reader, size int) *Reader
// NewReader 相當于 NewReaderSize(rd, 4096)
func NewReader(rd io.Reader) *Reader
// bufio.Reader 實現(xiàn)了如下接口:
// io.Reader
// io.WriterTo
// io.ByteScanner
// io.RuneScanner
// Peek 返回緩存的一個切片抠璃,該切片引用緩存中前 n 個字節(jié)的數(shù)據(jù)脱惰,
// 該操作不會將數(shù)據(jù)讀出,只是引用采盒,引用的數(shù)據(jù)在下一次讀取操作之
// 前是有效的磅氨。如果切片長度小于 n嫡纠,則返回一個錯誤信息說明原因。
// 如果 n 大于緩存的總大小左权,則返回 ErrBufferFull。
func (b *Reader) Peek(n int) ([]byte, error)
// Read 從 b 中讀出數(shù)據(jù)到 p 中蠢棱,返回讀出的字節(jié)數(shù)和遇到的錯誤。
// 如果緩存不為空泻仙,則只能讀出緩存中的數(shù)據(jù)玉转,不會從底層 io.Reader
// 中提取數(shù)據(jù)究抓,如果緩存為空,則:
// 1刺下、len(p) >= 緩存大小橘茉,則跳過緩存,直接從底層 io.Reader 中讀
// 出到 p 中擅腰。
// 2翁潘、len(p) < 緩存大小唐础,則先將數(shù)據(jù)從底層 io.Reader 中讀取到緩存
// 中一膨,再從緩存讀取到 p 中。
func (b *Reader) Read(p []byte) (n int, err error)
// Buffered 返回緩存中未讀取的數(shù)據(jù)的長度价淌。
func (b *Reader) Buffered() int
// Discard 跳過后續(xù)的 n 個字節(jié)的數(shù)據(jù)蝉衣,返回跳過的字節(jié)數(shù)巷蚪。
// 如果結(jié)果小于 n屁柏,將返回錯誤信息。
// 如果 n 小于緩存中的數(shù)據(jù)長度僧家,則不會從底層提取數(shù)據(jù)八拱。
func (b *Reader) Discard(n int) (discarded int, err error)
// ReadSlice 在 b 中查找 delim 并返回 delim 及其之前的所有數(shù)據(jù)。
// 該操作會讀出數(shù)據(jù)清蚀,返回的切片是已讀出的數(shù)據(jù)的引用轧铁,切片中的數(shù)據(jù)
// 在下一次讀取操作之前是有效的旦棉。
//
// 如果找到 delim,則返回查找結(jié)果救斑,err 返回 nil真屯。
// 如果未找到 delim,則:
// 1运沦、緩存不滿携添,則將緩存填滿后再次查找烈掠。
// 2缸托、緩存是滿的俐镐,則返回整個緩存佩抹,err 返回 ErrBufferFull。
//
// 如果未找到 delim 且遇到錯誤(通常是 io.EOF),則返回緩存中的所
// 有數(shù)據(jù)和遇到的錯誤廊勃。
//
// 因為返回的數(shù)據(jù)有可能被下一次的讀寫操作修改坡垫,所以大多數(shù)操作應該
// 使用 ReadBytes 或 ReadString,它們返回的是數(shù)據(jù)的拷貝堡妒。
func (b *Reader) ReadSlice(delim byte) (line []byte, err error)
// ReadLine 是一個低水平的行讀取原語皮迟,大多數(shù)情況下伏尼,應該使用
// ReadBytes('\n') 或 ReadString('\n')尉尾,或者使用一個 Scanner沙咏。
//
// ReadLine 通過調(diào)用 ReadSlice 方法實現(xiàn),返回的也是緩存的切片故河。用于
// 讀取一行數(shù)據(jù)忧勿,不包括行尾標記(\n 或 \r\n)瞻讽。
//
// 只要能讀出數(shù)據(jù)速勇,err 就為 nil烦磁。如果沒有數(shù)據(jù)可讀,則 isPrefix 返回
// false呕乎,err 返回 io.EOF猬仁。
//
// 如果找到行尾標記湿刽,則返回查找結(jié)果诈闺,isPrefix 返回 false雅镊。
// 如果未找到行尾標記,則:
// 1嗤军、緩存不滿叙赚,則將緩存填滿后再次查找震叮。
// 2苇瓣、緩存是滿的击罪,則返回整個緩存媳禁,isPrefix 返回 true画切。
//
// 整個數(shù)據(jù)尾部“有一個換行標記”和“沒有換行標記”的讀取結(jié)果是一樣竣稽。
//
// 如果 ReadLine 讀取到換行標記,則調(diào)用 UnreadByte 撤銷的是換行標記霍弹,
// 而不是返回的數(shù)據(jù)毫别。
func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error)
// ReadBytes 功能同 ReadSlice,只不過返回的是緩存的拷貝典格。
func (b *Reader) ReadBytes(delim byte) (line []byte, err error)
// ReadString 功能同 ReadBytes岛宦,只不過返回的是字符串。
func (b *Reader) ReadString(delim byte) (line string, err error)
// Reset 將 b 的底層 Reader 重新指定為 r耍缴,同時丟棄緩存中的所有數(shù)據(jù)恋博,復位
// 所有標記和錯誤信息齐佳。 bufio.Reader。
func (b *Reader) Reset(r io.Reader)
// 示例:Peek、Read疫衩、Discard、Buffered
func main() {
sr := strings.NewReader("ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890")
buf := bufio.NewReaderSize(sr, 0)
b := make([]byte, 10)
fmt.Println(buf.Buffered()) // 0
s, _ := buf.Peek(5)
s[0], s[1], s[2] = 'a', 'b', 'c'
fmt.Printf("%d %q\n", buf.Buffered(), s) // 16 "abcDE"
buf.Discard(1)
for n, err := 0, error(nil); err == nil; {
n, err = buf.Read(b)
fmt.Printf("%d %q %v\n", buf.Buffered(), b[:n], err)
}
// 5 "bcDEFGHIJK" <nil>
// 0 "LMNOP" <nil>
// 6 "QRSTUVWXYZ" <nil>
// 0 "123456" <nil>
// 0 "7890" <nil>
// 0 "" EOF
}
// 示例:ReadLine
func main() {
sr := strings.NewReader("ABCDEFGHIJKLMNOPQRSTUVWXYZ\n1234567890")
buf := bufio.NewReaderSize(sr, 0)
for line, isPrefix, err := []byte{0}, false, error(nil); len(line) > 0 && err == nil; {
line, isPrefix, err = buf.ReadLine()
fmt.Printf("%q %t %v\n", line, isPrefix, err)
}
// "ABCDEFGHIJKLMNOP" true <nil>
// "QRSTUVWXYZ" false <nil>
// "1234567890" false <nil>
// "" false EOF
fmt.Println("----------")
// 尾部有一個換行標記
buf = bufio.NewReaderSize(strings.NewReader("ABCDEFG\n"), 0)
for line, isPrefix, err := []byte{0}, false, error(nil); len(line) > 0 && err == nil; {
line, isPrefix, err = buf.ReadLine()
fmt.Printf("%q %t %v\n", line, isPrefix, err)
}
// "ABCDEFG" false <nil>
// "" false EOF
fmt.Println("----------")
// 尾部沒有換行標記
buf = bufio.NewReaderSize(strings.NewReader("ABCDEFG"), 0)
for line, isPrefix, err := []byte{0}, false, error(nil); len(line) > 0 && err == nil; {
line, isPrefix, err = buf.ReadLine()
fmt.Printf("%q %t %v\n", line, isPrefix, err)
}
// "ABCDEFG" false <nil>
// "" false EOF
}
// 示例:ReadSlice
func main() {
// 尾部有換行標記
buf := bufio.NewReaderSize(strings.NewReader("ABCDEFG\n"), 0)
for line, err := []byte{0}, error(nil); len(line) > 0 && err == nil; {
line, err = buf.ReadSlice('\n')
fmt.Printf("%q %v\n", line, err)
}
// "ABCDEFG\n" <nil>
// "" EOF
fmt.Println("----------")
// 尾部沒有換行標記
buf = bufio.NewReaderSize(strings.NewReader("ABCDEFG"), 0)
for line, err := []byte{0}, error(nil); len(line) > 0 && err == nil; {
line, err = buf.ReadSlice('\n')
fmt.Printf("%q %v\n", line, err)
}
// "ABCDEFG" EOF
}
2. bufio.Writer
type Writer struct { ... }
// NewWriterSize 將 wr 封裝成一個帶緩存的 bufio.Writer 對象宁否,
// 緩存大小由 size 指定(如果小于 4096 則會被設置為 4096)饱须。
// 如果 wr 的基類型就是有足夠緩存的 bufio.Writer 類型锅铅,則直接將
// wr 轉(zhuǎn)換為基類型返回。
func NewWriterSize(wr io.Writer, size int) *Writer
// NewWriter 相當于 NewWriterSize(wr, 4096)
func NewWriter(wr io.Writer) *Writer
// bufio.Writer 實現(xiàn)了如下接口:
// io.Writer
// io.ReaderFrom
// io.ByteWriter
// WriteString 功能同 Write,只不過寫入的是字符串
func (b *Writer) WriteString(s string) (int, error)
// WriteRune 向 b 寫入 r 的 UTF-8 編碼眼溶,返回 r 的編碼長度。
func (b *Writer) WriteRune(r rune) (size int, err error)
// Flush 將緩存中的數(shù)據(jù)提交到底層的 io.Writer 中
func (b *Writer) Flush() error
// Available 返回緩存中未使用的空間的長度
func (b *Writer) Available() int
// Buffered 返回緩存中未提交的數(shù)據(jù)的長度
func (b *Writer) Buffered() int
// Reset 將 b 的底層 Writer 重新指定為 w枢泰,同時丟棄緩存中的所有數(shù)據(jù)毛甲,復位
// 所有標記和錯誤信息。相當于創(chuàng)建了一個新的 bufio.Writer七咧。
func (b *Writer) Reset(w io.Writer)
------------------------------
// 示例:Available衬横、Buffered遥诉、WriteString、Flush
func main() {
buf := bufio.NewWriterSize(os.Stdout, 0)
fmt.Println(buf.Available(), buf.Buffered()) // 4096 0
buf.WriteString("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
fmt.Println(buf.Available(), buf.Buffered()) // 4070 26
// 緩存后統(tǒng)一輸出,避免終端頻繁刷新,影響速度
buf.Flush() // ABCDEFGHIJKLMNOPQRSTUVWXYZ
}
3. bufio.ReaderWriter
// 顧名思義: bufio.ReaderWriter綜合了Reader和Writer兩者的功能
// ReadWriter 集成了 bufio.Reader 和 bufio.Writer
type ReadWriter struct {
*Reader
*Writer
}
// NewReadWriter 將 r 和 w 封裝成一個 bufio.ReadWriter 對象
func NewReadWriter(r *Reader, w *Writer) *ReadWriter
4. bufio.Scanner
// 主要用于指定匹配函數(shù),進行文本掃描宪塔,返回匹配結(jié)果
// 自定義匹配函數(shù)中冠跷,支持正則表達式進行匹配
// Scanner 提供了一個方便的接口來讀取數(shù)據(jù)戚长,例如遍歷多行文本中的行。Scan 方法會通過
// 一個“匹配函數(shù)”讀取數(shù)據(jù)中符合要求的部分,跳過不符合要求的部分∥艽梗“匹配函數(shù)”由調(diào)
// 用者指定充蓝。本包中提供的匹配函數(shù)有“行匹配函數(shù)”、“字節(jié)匹配函數(shù)”、“字符匹配函數(shù)”
// 和“單詞匹配函數(shù)”湾趾,用戶也可以自定義“匹配函數(shù)”。默認的“匹配函數(shù)”為“行匹配函
// 數(shù)”,用于獲取數(shù)據(jù)中的一行內(nèi)容(不包括行尾標記)
//
// Scanner 使用了緩存岸浑,所以匹配部分的長度不能超出緩存的容量。默認緩存容量為 4096 -
// bufio.MaxScanTokenSize袁滥,用戶可以通過 Buffer 方法指定自定義緩存及其最大容量。
//
// Scan 在遇到下面的情況時會終止掃描并返回 false(掃描一旦終止,將無法再繼續(xù)):
// 1初家、遇到 io.EOF
// 2仆葡、遇到讀寫錯誤
// 3腰涧、“匹配部分”的長度超過了緩存的長度
//
// 如果需要對錯誤進行更多的控制滑臊,或“匹配部分”超出緩存容量,或需要連續(xù)掃描,則應該
// 使用 bufio.Reader
type Scanner struct { ... }
// NewScanner 創(chuàng)建一個 Scanner 來掃描 r律姨,默認匹配函數(shù)為 ScanLines荣赶。
func NewScanner(r io.Reader) *Scanner
// Buffer 用于設置自定義緩存及其可擴展范圍,如果 max 小于 len(buf)侣滩,則 buf 的尺寸將
// 固定不可調(diào)胜卤。Buffer 必須在第一次 Scan 之前設置悔醋,否則會引發(fā) panic蒂秘。
// 默認情況下冰抢,Scanner 會使用一個 4096 - bufio.MaxScanTokenSize 大小的內(nèi)部緩存。
func (s *Scanner) Buffer(buf []byte, max int)
// Split 用于設置“匹配函數(shù)”棘脐,這個函數(shù)必須在調(diào)用 Scan 前執(zhí)行。
func (s *Scanner) Split(split SplitFunc)
// SplitFunc 用來定義“匹配函數(shù)”构哺,data 是緩存中的數(shù)據(jù)。atEOF 標記數(shù)據(jù)是否讀完袱衷。
// advance 返回 data 中已處理的數(shù)據(jù)的長度脱吱。token 返回找到的“匹配部分”,“匹配
// 部分”可以是緩存的切片憔足,也可以是自己新建的數(shù)據(jù)(比如 bufio.errorRune)饼暑。“匹
// 配部分”將在 Scan 之后通過 Bytes 和 Text 反饋給用戶撰筷。err 返回錯誤信息。
//
// 如果在 data 中無法找到一個完整的“匹配部分”則應返回 (0, nil, nil),以便告訴
// Scanner 向緩存中填充更多數(shù)據(jù),然后再次掃描(Scan 會自動重新掃描)塘揣。如果緩存已
// 經(jīng)達到最大容量還沒有找到,則 Scan 會終止并返回 false。
// 如果 data 為空婴削,則“匹配函數(shù)”將不會被調(diào)用,意思是在“匹配函數(shù)”中不必考慮
// data 為空的情況敦姻。
//
// 如果 err != nil瘾境,掃描將終止,如果 err == ErrFinalToken镰惦,則 Scan 將返回 true迷守,
// 表示掃描正常結(jié)束,如果 err 是其它錯誤陨献,則 Scan 將返回 false,表示掃描出錯懂更。錯誤
// 信息可以在 Scan 之后通過 Err 方法獲取眨业。
//
// SplitFunc 的作用很簡單,從 data 中找出你感興趣的數(shù)據(jù)沮协,然后返回龄捡,同時返回已經(jīng)處理
// 的數(shù)據(jù)的長度。
type SplitFunc func(data []byte, atEOF bool) (advance int, token []byte, err error)
// Scan 開始一次掃描過程慷暂,如果匹配成功聘殖,可以通過 Bytes() 或 Text() 方法取出結(jié)果晨雳,
// 如果遇到錯誤,則終止掃描奸腺,并返回 false餐禁。
func (s *Scanner) Scan() bool
// Bytes 將最后一次掃描出的“匹配部分”作為一個切片引用返回,下一次的 Scan 操作會覆
// 蓋本次引用的內(nèi)容突照。
func (s *Scanner) Bytes() []byte
// Text 將最后一次掃描出的“匹配部分”作為字符串返回(返回副本)帮非。
func (s *Scanner) Text() string
// Err 返回掃描過程中遇到的非 EOF 錯誤,供用戶調(diào)用讹蘑,以便獲取錯誤信息末盔。
func (s *Scanner) Err() error
// ScanBytes 是一個“匹配函數(shù)”用來找出 data 中的單個字節(jié)并返回。
func ScanBytes(data []byte, atEOF bool) (advance int, token []byte, err error)
// ScanRunes 是一個“匹配函數(shù)”座慰,用來找出 data 中單個 UTF8 字符的編碼陨舱。如果 UTF8 編
// 碼錯誤,則 token 會返回 "\xef\xbf\xbd"(即:U+FFFD)版仔,但只消耗 data 中的一個字節(jié)游盲。
// 這使得調(diào)用者無法區(qū)分“真正的U+FFFD字符”和“解碼錯誤的返回值”。
func ScanRunes(data []byte, atEOF bool) (advance int, token []byte, err error)
// ScanLines 是一個“匹配函數(shù)”邦尊,用來找出 data 中的單行數(shù)據(jù)并返回(包括空行)背桐。
// 行尾標記可以是 \n 或 \r\n(返回值不包含行尾標記)
func ScanLines(data []byte, atEOF bool) (advance int, token []byte, err error)
// ScanWords 是一個“匹配函數(shù)”,用來找出 data 中以空白字符分隔的單詞蝉揍。
// 空白字符由 unicode.IsSpace 定義链峭。
func ScanWords(data []byte, atEOF bool) (advance int, token []byte, err error)
------------------------------
// 示例:掃描
func main() {
// 逗號分隔的字符串,最后一項為空
const input = "1,2,3,4,"
scanner := bufio.NewScanner(strings.NewReader(input))
// 定義匹配函數(shù)(查找逗號分隔的字符串)
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 {
// 告訴 Scanner 掃描結(jié)束又沾。
return 0, data, bufio.ErrFinalToken
} else {
// 告訴 Scanner 沒找到匹配項弊仪,讓 Scan 填充緩存后再次掃描。
return 0, nil, nil
}
}
// 指定匹配函數(shù)
scanner.Split(onComma)
// 開始掃描
for scanner.Scan() {
fmt.Printf("%q ", scanner.Text())
}
// 檢查是否因為遇到錯誤而結(jié)束
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, "reading input:", err)
}
}
--------------------------------------------------------------------------
// 示例:帶檢查掃描
func main() {
const input = "1234 5678 1234567901234567890 90"
scanner := bufio.NewScanner(strings.NewReader(input))
// 自定義匹配函數(shù)
split := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
// 獲取一個單詞
// ScanBytes杖刷、ScanWords励饵、ScanLines這些函數(shù)主用于篩選出相應的byte、word滑燃、line
// 然后用于自定義匹配函數(shù)中進行匹配
advance, token, err = bufio.ScanWords(data, atEOF)
// 判斷其能否轉(zhuǎn)換為整數(shù)役听,如果不能則返回錯誤
if err == nil && token != nil {
_, err = strconv.ParseInt(string(token), 10, 32)
}
// 這里包含了 return 0, nil, nil 的情況
return
}
// 設置匹配函數(shù)
scanner.Split(split)
// 開始掃描
for scanner.Scan() {
fmt.Printf("%s\n", scanner.Text())
}
// 掃描至1234567901234567890處,便會報錯拋出異常表窘,停止scan
if err := scanner.Err(); err != nil {
fmt.Printf("Invalid input: %s", err)
}
}
本文摘自:https://www.cnblogs.com/golove/p/3282667.html
5. bufio包個人理解:
- read操作 <-- bufio.Reader <-- 底層io.Reader(bytes典予,strings)
- write操作 --> bufio.Writer --> 底層io.Writer(bytes,strings)
- read&write操作 <--> bufio.ReadWriter --> 底層io.Reader&&io.Writer(bytes, strings)
- scan文本掃描(scan.Scan, scan.Bytes, scan.Text) <-- bufio.Scanner(文本掃描&緩存&自定義匹配函數(shù)) <-- 底層io.Reader(bytes乐严,strings)