新聞中心
?01 介紹
Go 語言標(biāo)準(zhǔn)庫 bufio? 是基于 Go 語言標(biāo)準(zhǔn)庫 io? 實(shí)現(xiàn)的,查看源碼可以發(fā)現(xiàn),實(shí)際上它是包裝了 io.Reader? 接口和 io.Writer 接口,并且實(shí)現(xiàn)它們。

bufio 顧名思義,就是在緩沖區(qū)讀寫數(shù)據(jù),比直接讀寫文件或網(wǎng)絡(luò)中的數(shù)據(jù),性能更好些。
本文我們介紹 bufio? 的相關(guān)內(nèi)容,建議讀者朋友們最好是先了解一下 io 的相關(guān)內(nèi)容。
02 標(biāo)準(zhǔn)庫 bufio 的數(shù)據(jù)類型
查看標(biāo)準(zhǔn)庫 `bufio` 的文檔[1],它的數(shù)據(jù)類型主要有 bufio.Reader、bufio.Writer、bufio.ReadWriter? 和 bufio.Scanner。
我們以 bufio.Reader 為例,介紹它的數(shù)據(jù)結(jié)構(gòu)、初始化方式和提供的方法。
bufio.Reader 的數(shù)據(jù)結(jié)構(gòu):
type Reader struct {
buf []byte
rd io.Reader
r, w int
err error
lastByte int
lastRuneSize int
}閱讀源碼,我們可以發(fā)現(xiàn) bufio.Reader 中包含的字段:
- buf []byte 緩沖區(qū)。
- rd io.Reader 緩沖區(qū)的數(shù)據(jù)源。
- r,w int 緩沖區(qū)讀寫索引位置。
- err error 錯(cuò)誤。
- lastByte int 未讀字節(jié)的上一個(gè)字節(jié)。
- lastRuneSize 未讀字符的上一個(gè)字符的大小。
bufio.Reader 的初始化方式:
使用 bufio.Reader? 時(shí),需要先初始化,bufio? 包提供了兩個(gè)初始化的函數(shù),分別是 NewReaderSize? 和 NewReader。
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 {
size = minReadBufferSize
}
r := new(Reader)
r.reset(make([]byte, size), rd)
return r
}
func NewReader(rd io.Reader) *Reader {
return NewReaderSize(rd, defaultBufSize)
}閱讀源碼,我們可以發(fā)現(xiàn)這兩個(gè)函數(shù)的返回值都是 *bufio.Reader 類型。
其中 NewReader? 是包裝了 NewReaderSize 函數(shù),給定了一個(gè)默認(rèn)值 4096,設(shè)置讀緩沖區(qū)的大小。
如果我們使用默認(rèn)值,一般選擇使用 NewReader 函數(shù)。
如果不想使用默認(rèn)值,可以選擇使用 NewReaderSize 函數(shù)。
bufio.Reader 提供的方法:
bufio.Reader? 提供了 15 個(gè)方法,我們介紹兩個(gè)比較常用的方法,分別是 Read? 和 ReadBytes。
func (b *Reader) Read(p []byte) (n int, err error) {
// 省略代碼 ...
if b.r == b.w {
if b.err != nil {
return 0, b.readErr()
}
if len(p) >= len(b.buf) {
// Large read, empty buffer.
// Read directly into p to avoid copy.
n, b.err = b.rd.Read(p)
if n < 0 {
panic(errNegativeRead)
}
if n > 0 {
b.lastByte = int(p[n-1])
b.lastRuneSize = -1
}
return n, b.readErr()
}
// 省略代碼 ...
b.w += n
}
// copy as much as we can
// Note: if the slice panics here, it is probably because
// the underlying reader returned a bad count. See issue 49795.
n = copy(p, b.buf[b.r:b.w])
b.r += n
b.lastByte = int(b.buf[b.r-1])
b.lastRuneSize = -1
return n, nil
}閱讀源碼,我們可以發(fā)現(xiàn) Read? 方法是將緩沖區(qū)中的數(shù)據(jù),讀取到 p 中,并返回讀取的字節(jié)大小和錯(cuò)誤。
func (b *Reader) ReadBytes(delim byte) ([]byte, error) {
full, frag, n, err := b.collectFragments(delim)
// Allocate new buffer to hold the full pieces and the fragment.
buf := make([]byte, n)
n = 0
// Copy full pieces and fragment in.
for i := range full {
n += copy(buf[n:], full[i])
}
copy(buf[n:], frag)
return buf, err
}閱讀源碼,我們可以發(fā)現(xiàn) ReadBytes? 方法是讀取緩沖區(qū)中的數(shù)據(jù)截止到分隔符 delim 的位置,并返回?cái)?shù)據(jù)和錯(cuò)誤。
使用示例:
Read 方法
func main() {
f, _ := os.Open("/Users/frank/GolandProjects/go-package/lesson14/file.txt")
defer f.Close()
r := bufio.NewReader(f)
p := make([]byte, 12)
index, _ := r.Read(p)
fmt.Println(index)
fmt.Println(string(p[:index]))
}需要注意的是,p 字節(jié)切片的長(zhǎng)度,一個(gè)中文字符是 3 個(gè)字節(jié),一個(gè)英文字符是 1 個(gè)字節(jié)。
ReadBytes 方法
func main() {
f, _ := os.Open("/Users/frank/GolandProjects/go-package/lesson14/file.txt")
defer f.Close()
r := bufio.NewReader(f)
bs, _ := r.ReadBytes('\n')
fmt.Println(string(bs))
}需要注意的是,分隔符參數(shù)是 byte 類型,使用單引號(hào)。
03 總結(jié)
本文我們以 bufio.Reader? 為例,介紹標(biāo)準(zhǔn)庫 bufio 的數(shù)據(jù)類型、初始化方式和提供的方法。
實(shí)際上標(biāo)準(zhǔn)庫 bufio 使用非常簡(jiǎn)單,但是想要避免踩 “坑”,讀者朋友們最好是熟讀標(biāo)準(zhǔn)庫 `bufio` 的源碼[2]。
參考資料
[1]標(biāo)準(zhǔn)庫 bufio? 的文檔: https://pkg.go.dev/bufio@go1.20.2
[2]標(biāo)準(zhǔn)庫 bufio? 的源碼: https://cs.opensource.google/go/go/+/refs/tags/go1.20.2:src/bufio/
名稱欄目:Go語言標(biāo)準(zhǔn)庫bufio詳解
URL地址:http://m.5511xx.com/article/ccccedp.html


咨詢
建站咨詢
