This is a creation in Article, where the information may have evolved or changed.
Bufio Data Read attention item
In the first chapter of Go Bible bufio-cache io, there is an example, the non-read source code is not easy to understand.
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}
Printing results:
the line:http://studygolang.com. the line:It is the home of gophersIt 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}
Printing results:
the line:http://studygolang.com. the line:http://studygolang.com. It is the home of gophers, yes or no ?
The output of the comparison, the crash glasses, incredibly have no \n
results, the gap is so large.
In-depth analysis of source code:
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 } ...}
These are the key points of the code, which we will now discuss separately:
- For the first demo, the second line returns
It is the home of gophers, yes or no ?
, expecting to be returned http://studygolang.com.
.
- The analysis is as follows: Read reader for the second time. Readslice, Bytes. Indexbyte did not find the second
\n
, so the returned index i is less than 0, then the Fill method will be executed, because the first time the data is read, so the B.R is definitely greater than 0, so the copy operation, buf the underlying array has changed into a new write B.BUF[B.R : B.W] Value, but be aware that line length and capacity is constant, so there will be truncation or insufficient situation.
- For the second demo, the desired and expected values are the same
- The analysis is as follows: Read reader for the second time. Readslice, Bytes. Indexbyte can find the second one
\n
, then return directly, write without modifying the buf underlying data, which makes the line underlying array unchanged.
Conclusion: So when we use the standard library, it is not very clear how to make it better, otherwise it is easy to make mistakes. Here's how to circumvent readslice errors
func (b *Reader) ReadString(delim byte) (string, error) // 安全func (b *Reader) ReadBytes(delim byte) ([]byte, error) // 安全, 因为返回的[]byte是用make新分配内存空间