io.Reader in depth

Mat Ryer
Mat Ryer
Dec 17, 2015 · 3 min read

Single method interfaces end up being extremely powerful — more so than even the language creators thought.

This article aims to convince you to use io.Reader in your own code wherever you can.

Let’s have a look at io.Reader:

type Reader interface {
Read(p []byte) (n int, err error)
}

Pretty simple; a Reader is any type that implements the `Read` method.

Check out the comments from the standard library documentation for a little more context for Reader.

For those unfamiliar with these interfaces; you pass in a slice of bytes, and Read is asked to fill it with its data — which is does until it runs out of data. It returns the number of bytes read (in `n`) or an error if something goes wrong. Additionally, if it has finished reading, it will return a special marker error called `io.EOF` (end of file).

Examples of readers

There are many kinds of Reader types available in the standard library, and you’ve almost certainly used at least one of them.

If you open a file for reading, the object returned is an `os.File`, which is a Reader (it implements the Read method):

var r io.Reader
var err error
r, err = os.Open("file.txt")

You can also make a Reader from a normal string using `strings.NewReader`:

var r io.Reader
r = strings.NewReader("Read will return these bytes")

The body data from an `http.Request` is a Reader:

var r io.Reader
r = request.Body

A bytes.Buffer is a Reader:

var r io.Reader
var buf bytes.Buffer
r = &buf

There are many more throughout the standard library — and in most third-party packages too, since it’s good practice to use them wherever you can.

Using readers

Now we have a few Reader types — let’s explore ways in which they can be used.

You can read from them directly (this turns out to be the least useful use case):

p := make([]byte, 256)
n, err := r.Read(p)

`ioutil.ReadAll` lets you read everything from a Reader, and get the raw []byte data:

b, err := ioutil.ReadAll(r)

`io.Copy` lets you read ALL bytes from an io.Reader, and write it to an io.Writer:

n, err := io.Copy(w, r)

The JSON decoder lets you decode directly from a Reader:

err := json.NewDecoder(r).Decode(v)

If you’re reading bytes that have been gzipped, you can wrap the io.Reader in a gzip.Reader:

r = gzip.NewReader(r)

Now reading from the new reader will decompress as you read.

Take io.Reader when you can

If you’re designing a package or utility (even if it’s an internal thing that nobody will ever see) rather than taking in strings or []byte slices, consider taking in an io.Reader if you can for data sources. Because suddenly, your code will work with every type that implements io.Reader.

So this:

func Reverse(s string) (string, error)

Could become:

func Reverse(r io.Reader) io.Reader

Then if someone wants to use it with a string, they can:

r = Reverse(strings.NewReader("Make me backwards"))

But they can also use it with a file:

f, err := os.Open("file.txt")
if err != nil {
log.Fatalln(err)
}
r = Reverse(f)

Or a web request:

func handle(w http.ResponseWriter, r *http.Request) {  rev := Reverse(r.Body)  // etc...
}

Use io.Reader (and io.Writer) whenever you’re dealing with streams of data. And this goes for all single method interfaces from the standard library.

Mat Ryer

Written by

Mat Ryer

Founder at MachineBox.io — Gopher, developer, speaker, author — BitBar app https://getbitbar.com — Author of Go Programming Blueprints

Mat Ryer

Written by

Mat Ryer

Founder at MachineBox.io — Gopher, developer, speaker, author — BitBar app https://getbitbar.com — Author of Go Programming Blueprints

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store