Skip to main content

Our first Reader

To understand Readers and Writers I will go through the implementations of these interfaces and see how they are used.

When coding you mostly use already defined implementations, so it's useful to go through most of them and see how they are used.

That being said, let's check out the first concrete implementation of io.Reader: the strings.Reader.

strings.Reader

The simplest reader is a strings.Reader.

Keep in mind that strings.Reader is not the same as io.Reader. io.Reader is an interface and strings.Reader is one of the many concrete implementations of that interface.

The bellow example is taken from the Go Tour:

It creates a new Reader with:

  r := strings.NewReader("Hello, Reader!")

and then consumes its output 8 bytes at a time:

package main

import (
"fmt"
"io"
"strings"
)

func main() {
r := strings.NewReader("Hello, Reader!")

b := make([]byte, 8)
for {
n, err := r.Read(b)
fmt.Printf("n = %v err = %v b = %v\n", n, err, b)
fmt.Printf("b[:n] = %q\n", b[:n])
if err == io.EOF {
break
}
}
}

run in Playground

Output:

n = 8 err = <nil> b = [72 101 108 108 111 44 32 82]
b[:n] = "Hello, R"
n = 6 err = <nil> b = [101 97 100 101 114 33 32 82]
b[:n] = "eader!"
n = 0 err = EOF b = [101 97 100 101 114 33 32 82]
b[:n] = ""

io.ReadFull

Above, we used directly the .Read() method to read data from our reader. You won't use this method that often.

io.ReadFull is used when you want to read an exact number of bytes from our reader .

package main

import (
"fmt"
"io"
"log"
"strings"
)

func main() {
r := strings.NewReader("Hello, Reader!")

buf := make([]byte, 5)

if _, err := io.ReadFull(r, buf); err != nil {
log.Fatal(err)
}

fmt.Println(buf)
fmt.Println(string(buf))
}

run in Playground

[72 101 108 108 111]
Hello

io.ReadAll

The io.ReadAll function reads all bytes from your Reader:

package main

import (
"fmt"
"io"
"log"
"strings"
)

func main() {
r := strings.NewReader("Hello, Reader!")

data, err := io.ReadAll(r)

if err != nil {
log.Fatal(err)
}

fmt.Println(data)
fmt.Println(string(data))
}
[72 101 108 108 111 44 32 82 101 97 100 101 114 33]
Hello, Reader!

Conclusion

So far you've learned about the strings.Reader and also how to read an exact number of bytes with io.ReadFull or how to read all bytes from it with io.ReadAll.

Keep in mind strings.Reader is just one of the many implementations of io.Reader. You can use io.ReadFull and io.ReadAll functions on all io.Reader implementations.