Go聖經-學習筆記入門bufio

bufio數據讀取注意項

在go聖經第一章節 bufio-緩存IO,有個例子,不讀源碼不容易理解。golang

DEMO 1

func main(){
    reader :=bufio.NewReader(
    strings.NewReader(""http://studygolang.com. \nIt is the home of gophers, yes or no ?"),
    )
    
    line, _ := reader.ReadSlice('\n')
    fmt.Printf("line=%s", line) // 注意點:bufio.ReadSlice會把'\n'讀取進來, 因此自帶換行
    n, _ := reader.ReadSlice('\n')
    fmt.Printf("the line:%s\n", line) // 猜猜line返回結果
    fmt.Println(string(n)) // 沒有讀取到換行符
    return
}

打印結果:數組

the line:http://studygolang.com. 
the line:It is the home of gophers
It is the home of gophers, yes or no ?

DEMO 2

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
     lastRuneSize int
 }
 
func main(){
    reader :=bufio.NewReader(
    strings.NewReader(""http://studygolang.com. \nIt is the home of gophers, yes or no ?\n"),
    ) // 多加一個`\n`
    
    line, _ := reader.ReadSlice('\n')
    fmt.Printf("line=%s", line) // 注意點:bufio.ReadSlice會把'\n'讀取進來, 因此自帶換行
    n, _ := reader.ReadSlice('\n')
    fmt.Printf("the line:%s\n", line) // 猜猜line返回結果
    fmt.Println(string(n)) // 讀取到換行符
    return
}

打印結果:緩存

the line:http://studygolang.com. 
the line:http://studygolang.com. 

It is the home of gophers, yes or no ?

其輸出結果對比,大跌眼鏡,竟然有無\n結果,差距這麼大。安全

深刻分析源碼:ide

func (b *Reader) ReadSlice(delim byte) (line []byte, err error){
    for {
        if i:=bytes.IndexBytes(b.buf[b.r:b.w], delim); i>= 0{
            line = b.buf[b.r : b.r+i+1]
            b.r =i+1
            break
        }
        ...
        b.fill() // 若是buf已經讀完,須要再次從b.rd中讀取新的數據
    }
}

func (b *Reader) fill() {
    if b.r > 0 {
        copy(b.buf, b.buf[b.r: b:w])
        b.w -=b.r
        b.r=0
    }
    
    ...
}

以上爲代碼關鍵點,咱們如今分別討論:code

  • 對於第一個DEMO,第二個line返回的是It is the home of gophers, yes or no ?,指望是返回 http://studygolang.com. .
    • 分析以下:由於第二次讀取reader.ReadSlice時,bytes.IndexByte沒有發現第二個\n, 因此返回的索引i小於0, 則會執行fill方法,則時由於第一次讀取了數據,因此b.r確定大於0,因此執行了copy操做,buf底層數組發生了變化,變成了新寫入的b.buf[b.r: b.w]值,可是要注意,line的長度和容量是不變的,因此會存在截斷或者不足的狀況。
  • 對於第二個DEMO,但願和指望的值是相同的
    • 分析以下:由於第二次讀取reader.ReadSlice時,bytes.IndexByte能夠發現第二個\n, 則直接返回,寫沒有修改buf底層數據,也就使得line底層數組沒有發生變化。

結論:因此咱們在使用標準庫時,不是很明白的方法要搞清楚才能好一些,否則容易犯錯誤。如下是規避ReadSlice錯誤的方法索引

func (b *Reader) ReadString(delim byte) (string, error) // 安全
func (b *Reader) ReadBytes(delim byte) ([]byte, error) // 安全, 由於返回的[]byte是用make新分配內存空間
相關文章
相關標籤/搜索