Reading specific number of bytes from a buffered reader in golang
func (b *Reader) Read(p []byte) (n int, err error)
http://golang.org/pkg/bufio/#Reader.Read
The number of bytes read will be limited to len(p)
TLDR:
my42bytes, err := ioutil.ReadAll(io.LimitReader(myReader, 42))
Full answer:
@monicuta mentioned io.ReadFull
which works great. Here I provide another method. It works by chaining ioutil.ReadAll
and io.LimitReader
together. Let's read the doc first:
$ go doc ioutil.ReadAll func ReadAll(r io.Reader) ([]byte, error) ReadAll reads from r until an error or EOF and returns the data it read. A successful call returns err == nil, not err == EOF. Because ReadAll is defined to read from src until EOF, it does not treat an EOF from Read as an error to be reported. $ go doc io.LimitReader func LimitReader(r Reader, n int64) Reader LimitReader returns a Reader that reads from r but stops with EOF after n bytes. The underlying implementation is a *LimitedReader.
So if you want to get 42 bytes from myReader
, you do this
import (
"io"
"io/ioutil"
)
func main() {
// myReader := ...
my42bytes, err := ioutil.ReadAll(io.LimitReader(myReader, 42))
if err != nil {
panic(err)
}
//...
}
Here is the equivalent code with io.ReadFull
$ go doc io.ReadFull func ReadFull(r Reader, buf []byte) (n int, err error) ReadFull reads exactly len(buf) bytes from r into buf. It returns the number of bytes copied and an error if fewer bytes were read. The error is EOF only if no bytes were read. If an EOF happens after reading some but not all the bytes, ReadFull returns ErrUnexpectedEOF. On return, n == len(buf) if and only if err == nil. If r returns an error having read at least len(buf) bytes, the error is dropped.
import (
"io"
)
func main() {
// myReader := ...
buf := make([]byte, 42)
_, err := io.ReadFull(myReader, buf)
if err != nil {
panic(err)
}
//...
}
Compared to io.ReadFull
, an advantage is that you don't need to manually make a buf
, where len(buf)
is the number of bytes you want to read, then pass buf
as an argument when you Read
Instead you simply tell io.LimitReader
you want at most 42 bytes from myReader
, and call ioutil.ReadAll
to read them all, returning the result as a slice of bytes. If successful, the returned slice is guaranteed to be of length 42.
Note that the bufio.Read
method calls the underlying io.Read
at most once, meaning that it can return n < len(p)
, without reaching EOF. If you want to read exactly len(p)
bytes or fail with an error, you can use io.ReadFull
like this:
n, err := io.ReadFull(reader, p)
This works even if the reader is buffered.