標準庫bufio個人詳解
本文是我有通俗的語言寫的如果有誤請指出。
先看bufio官方文件
https://studygolang.com/pkgdoc文件地址
主要分三部分Reader、Writer、Scanner
分別是讀資料、寫資料和掃描器三種資料型別的相關操作 這個掃描後面會詳細說我開始也沒弄明白其實很簡單。
Reader
func NewReaderSize
func NewReaderSize(rd io.Reader, size int) *Reader
NewReaderSize建立一個具有最少有size尺寸的緩衝、從r讀取的*Reader。如果引數r已經是一個具有足夠大緩衝的* Reader型別值,會返回r。
解釋:看官方解釋這個方法可能不太容易懂,這個意思就是就是你可以給*Reader自定義一個size大小的緩衝區,*Reader每次從底層io.Reader(也就是你那個檔案或者流)中預讀size大小的資料到緩衝區中(可能讀不滿),然後你每次讀資料實際是從這個緩衝區中拿資料。
下面是NewReaderSize原始碼
func NewReaderSize(rd io.Reader, size int) *Reader { // Is it already a Reader? b, ok := rd.(*Reader) if ok && len(b.buf) >= size { return b } if size < minReadBufferSize { //minReadBufferSize==16 size = minReadBufferSize } r := new(Reader) r.reset(make([]byte, size), rd) return r }
r.reset 初始化了一個*Reader 返回大小是size。
func NewReader
func NewReader(rd io.Reader) *Reader
NewReader建立一個具有預設大小緩衝、從r讀取的*Reader。
解釋:那這個NewReader就很好解釋了 和NewReaderSize基本一樣就是緩衝區大小是預設設定好的
func (*Reader) Peek
func (b *Reader) Peek(n int) ([]byte, error)
解釋:Peek就是返回快取的一個切片,該切片引用快取中的前N個位元組的資料,如果n大於總大小,則返回能讀到的位元組數的資料。
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。
解釋:如果快取不為空則直接從快取中讀資料不會從底層io.Reader讀,如果快取為空len(p)>快取大小,則直接從底層io.Reader讀資料到p。
如果len(p)<快取大小,則先從底層io.Reader中讀資料到快取再到p。
主要就這幾個 還有幾個文件寫的都很清楚易懂我就不多寫了。
Writer型別的方法和Reader型別的方法差不多也很易懂主要就一個Flush要注意。
func (*Writer) Flush
func (b *Writer) Flush() error
Flush方法將緩衝中的資料寫入下層的io.Writer介面。
和Reader是倒過來的,Writer每次寫資料是先寫入緩衝區的,程序緩衝區填滿後,通過程序緩衝寫入到核心緩衝再寫入到磁碟,使用Flush就不等填滿直接走寫入流程了,保證你的資料及時寫入檔案。
解釋:scanner型別掃描器 官方的說法很複雜,我也沒太看懂找了很多資料,其實就是你在資料傳輸的時候時候使用“分隔符”,scanner型別可以通過分隔符逐個迭代你的資料。
上面4個函式func Scan…… 就是分隔符的判斷函式這4個是給你預設好的,你也可以按照自己的需求改寫。
怎麼改寫呢,看下面
func (*Scanner) Split
func (s *Scanner) Split(split SplitFunc)
這個Split方法就是設定你這個scanner的用哪個SplitFunc型別的函式
在看下面這個SpliFunc型別的函式簽名
type SplitFunc func(data []byte, atEOF bool) (advance int, token []byte, err error)
照著這個格式寫一個不就得了麼,當然具體寫法給出了但是你不會?沒關係咱看一下官方是咋寫的。
https://github.com/golang/go/blob/master/src/bufio/scan.go?name=release#57官方原始碼地址
func ScanLines(data []byte, atEOF bool) (advance int, token []byte, err error) { if atEOF && len(data) == 0 { return 0, nil, nil } if i := bytes.IndexByte(data, '\n'); i >= 0 { // We have a full newline-terminated line. return i + 1, dropCR(data[0:i]), nil } // If we're at EOF, we have a final, non-terminated line. Return it. if atEOF { return len(data), dropCR(data), nil } // Request more data. return 0, nil, nil }
看bytes.IndexByte(data, '\n');這段不就是在找行尾嘛 比如你想改成以“;”為分隔符的就改成bytes.IndexByte(data, ';');不就得了麼
func main(){ scanner:=bufio.NewScanner( strings.NewReader("abcdefg\nhigklmn"), ) scanner.Split(ScanLines) //這裡可以隨意選擇用哪個函式也可以自定義,可以不指定預設為\n做分隔符
for scanner.Scan(){
fmt.Println(scanner.Text())
}
}
到此為止拉~
&n