Go: The io.Reader interface

The io.Reader interface represents an entity from which you can read a stream of bytes:

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

Read reads up to len(buf) bytes into buf and returns the number of bytes read; it returns an io.EOF error when the stream ends.

Example

The standard library provides numerous Reader implementations (including in-memory byte buffers, files and network connections), and Readers are accepted as input by many utilities (including the HTTP client and server implementations).

As an example, you can create a Reader from a string using the strings.Reader function and then pass the Reader directly to the http.Post function in package net/http. The Reader is then used as the source for the data to be posted:

r := strings.NewReader("my request")
resp, err := http.Post("http://foo.bar", "application/x-www-form-urlencoded", r)

Since http.Post uses a Reader instead of a []byte it’s trivial to, for instance, use the contents of a file.

Reading directly from a byte stream

You can use the Read function directly (this is the least common use case):

r := strings.NewReader("abcde")

buf := make([]byte, 4)
for {
	n, err := r.Read(buf)
	fmt.Println(n, err, buf[:n])
	if err == io.EOF {
		break
	}
}
// Output:
// 4 <nil> [97 98 99 100]
// 1 <nil> [101]
// 0 EOF []

Use io.ReadFull to read exactly len(buf) bytes into buf:

r := strings.NewReader("abcde")

buf := make([]byte, 4)
if _, err := io.ReadFull(r, buf); err != nil {
	log.Fatal(err)
}
fmt.Println(buf)

if _, err := io.ReadFull(r, buf); err != nil {
	fmt.Println(err)
}
// Output:
// [97 98 99 100]
// unexpected EOF

Use ioutil.ReadAll to read everything:

r := strings.NewReader("abcde")

buf, err := ioutil.ReadAll(r)
if err != nil {
	log.Fatal(err)
}
fmt.Println(buf)
// Output: [97 98 99 100 101]

Buffered reading and scanning

The bufio.Reader and bufio.Scanner types wrap a Reader creating another Reader that also implements the interface but provides buffering and some help for textual input.

In this example we use a bufio.Scanner to count the number of words in a text:

const input = `Beware of bugs in the above code;
I have only proved it correct, not tried it.`

scanner := bufio.NewScanner(strings.NewReader(input))
scanner.Split(bufio.ScanWords) // Set the split function.

count := 0
for scanner.Scan() {
	count++
}
if err := scanner.Err(); err != nil {
	fmt.Println(err)
}
fmt.Println(count)
// Output: 16

Comments