AchillesHeel
AchillesHeel

Reputation: 85

How Go buffer read data from io.Reader?

I'm learning for Go bufio package, and confused by a code snippet below:

1  s1 := strings.NewReader(strings.Repeat("a", 16) + strings.Repeat("b", 16))
2  r := bufio.NewReaderSize(s1, 16)
3  b, _ := r.Peek(3)
4  fmt.Printf("%q\n", b)
5  r.Read(make([]byte, 16))
6  r.Read(make([]byte, 15))
7  fmt.Printf("%q\n", b)

// "aaa"
// "bbb"

Isn't that r in line 2 an empty []byte? Why can user r.Peek(3) to figure out the "aaa" result?

Assume the bufio.NewReaderSize(s1, 16) can Read 16 bytes from Reader s1, this make line 3 reasonable; Why use twice r.Read() in line5 and line6?

And Isn't that the undelying array of r in line 5 is "aaaaaaaaaaaaaaaa", and line6 became the "bbbbbbbbbbbbbbb"?

Or maybe the underlying array of r always be "aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb"?

If you can give me any inspiration, Thank you for your help.

Upvotes: 0

Views: 2846

Answers (1)

Wagner Riffel
Wagner Riffel

Reputation: 352

Isn't that r in line 2 an empty []byte? Why can user r.Peek(3) to figure out the "aaa" result?

If the underlying buffer is empty or has not enough space left to satisfy Peek(n), bufio.Reader will call its underlying io.Reader Read method to fill the buffer, you can check this by extending the returned slice from Peek, b , _ := r.Peek(1); fmt.Printf("%q\n", b[:cap(b)]).

The problem is that you're misusing the package, there is no guarantee nor API to get the underlying array or even that it's used, Peek returns the underlying array in a slice only to avoid a copy/memory allocation, in fact bufio may just ignore buffering and call the underlying reader directly, see: https://go.dev/play/p/WT6AUfEno3t

As noted in Peek documentation, the returned slice from Peek is only valid values until a call to Read, to correctly get data from Reader, use the Read method, not tricks to get its underlying buffer.

Upvotes: 0

Related Questions