在go聖經第一章節 bufio-緩存IO,有個例子,不讀源碼不容易理解。golang
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 ?
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
It is the home of gophers, yes or no ?
,指望是返回 http://studygolang.com.
.
\n
, 因此返回的索引i小於0, 則會執行fill方法,則時由於第一次讀取了數據,因此b.r確定大於0,因此執行了copy操做,buf底層數組發生了變化,變成了新寫入的b.buf[b.r: b.w]值,可是要注意,line的長度和容量是不變的,因此會存在截斷或者不足的狀況。\n
, 則直接返回,寫沒有修改buf底層數據,也就使得line底層數組沒有發生變化。結論:因此咱們在使用標準庫時,不是很明白的方法要搞清楚才能好一些,否則容易犯錯誤。如下是規避ReadSlice錯誤的方法索引
func (b *Reader) ReadString(delim byte) (string, error) // 安全 func (b *Reader) ReadBytes(delim byte) ([]byte, error) // 安全, 由於返回的[]byte是用make新分配內存空間