6
func foo(buf *bytes.Buffer) {
    fmt.Println("0: ", len(buf.Bytes()))
    ioutil.ReadAll(buf)
    fmt.Println("1: ", len(buf.Bytes()))
}

The code shows the correct length the first time, but the second times it shows the length is zero.

Dave C
  • 7,729
  • 4
  • 49
  • 65
joy
  • 85
  • 1
  • 4

1 Answers1

10

Reading from a bytes.Buffer drains or consumes the bytes that were read. This means if you try to read again, those will not be returned.

Buffer.Bytes() returns the unread portion of the buffer, so it is the expected result for you to see 0 length after everything has been read (this is exactly what ioutil.ReadAll() does).


What if you just want to "peek" and not really "read" bytes?

There is no "peek" functionality in bytes.Buffer. The easiest would be to get the bytes of the buffer, and construct another bytes.Buffer from it and read from the new buffer.

It could look something like this:

func peek(buf *bytes.Buffer, b []byte) (int, error) {
    buf2 := bytes.NewBuffer(buf.Bytes())
    return buf2.Read(b)
}

peek() in action:

Error checks omitted for simplicity:

buf := &bytes.Buffer{}

buf.WriteString("Hello")
fmt.Printf("Len: %d, Content: %s\n", buf.Len(), buf)

fmt.Println("\nPeeking...")
data := make([]byte, 4)
peek(buf, data)
fmt.Printf("Peeked: %s\n", data)
fmt.Printf("Len: %d, Content: %s\n", buf.Len(), buf)

fmt.Println("\nReading...")
data = make([]byte, buf.Len())
buf.Read(data)
fmt.Printf("Read: %s\n", data)
fmt.Printf("Len: %d, Content: %s\n", buf.Len(), buf)

Output (try it on the Go Playground):

Len: 5, Content: Hello

Peeking...
Peeked: Hell
Len: 5, Content: Hello

Reading...
Read: Hello
Len: 0, Content: 
icza
  • 389,944
  • 63
  • 907
  • 827
  • 1
    Thank you very much. I understand. And Does has any ways that read its content second times? – joy Jun 18 '15 at 08:59
  • 1
    This approach doesn't copy anything (other than data in to b), just creates a new buffer. Only way I can see this being faster is to do "return copy(buf.Bytes(),b),nil" which has the same effect but doesn't allocate a new buffer. not sure which is actually faster. (guessing the copy is) – David Budworth Jun 18 '15 at 12:08
  • @DavidBudworth Yeah, you're right. `Buffer.Bytes()` just returns a slice sharing the same underlying array. So it's not bad performance-wise at all. – icza Jun 18 '15 at 12:25
  • Seems like there be problems using this approach for network buffers that probably don't have all the data in `Buffer.Bytes()` yet. – Xeoncross May 30 '17 at 17:50
  • @Xeoncross `bytes.Buffer` is an in-memory buffer, it has nothing to do with networking. In case of a network, we have to take care of "replaying" the data read and inspected. An example can be found in this answer: [Golang read request body](https://stackoverflow.com/questions/43021058/golang-read-request-body/43021236#43021236) – icza May 30 '17 at 23:17