← Back to Go Course | Chapter 7: Interfaces | Lesson 6 of 7

io.Reader and io.Writer

io.Reader and io.Writer are like universal plug shapes for data -- anything that can hand out bytes fits one, and anything that can accept bytes fits the other, no matter what's on the other end.

The io.Writer Interface

io.Writer requires a single method, Write(p []byte) (int, error), which accepts a slice of bytes and reports how many were written. Because it's so minimal, everything from files to network sockets to fmt.Fprintf's destination can implement it.

Example: The io.Writer Interface

markup
package main

import (
	"fmt"
	"os"
)

func main() {
	fmt.Fprintln(os.Stdout, "written through an io.Writer")
}

The io.Reader Interface

io.Reader requires Read(p []byte) (int, error), which fills the given buffer with as much data as is available and reports how many bytes it wrote, plus an error (io.EOF when the stream is finished).

Note: Read can return fewer bytes than the buffer's length -- always check n, not just err.

Example: The io.Reader Interface

markup
package main

import (
	"fmt"
	"strings"
)

func main() {
	r := strings.NewReader("Go rocks")
	buf := make([]byte, 4)
	n, _ := r.Read(buf)
	fmt.Println(n, string(buf[:n]))
}

Reading Until EOF

Because a single Read call may not return the entire stream, code that wants everything typically loops, calling Read repeatedly until it receives the io.EOF error, or uses a helper like io.ReadAll that does this for you.

Example: Reading Until EOF

markup
package main

import (
	"fmt"
	"io/ioutil"
	"strings"
)

func main() {
	r := strings.NewReader("Hello, io.Reader!")
	data, err := ioutil.ReadAll(r)
	if err != nil {
		fmt.Println("error:", err)
		return
	}
	fmt.Println(string(data))
}
Common Mistakes
  1. Assuming Read always fills the entire buffer in one call -- it can return fewer bytes than requested, and callers must check n and loop if needed.
  2. Ignoring the io.EOF error from Read, which signals the end of the stream rather than a real error condition.
  3. Forgetting Write must return the number of bytes actually written, and callers should verify it matches len(p).
Chapter Summary
  • io.Reader defines Read(p []byte) (n int, err error); io.Writer defines Write(p []byte) (n int, err error).
  • These tiny, one-method interfaces let files, network connections, and in-memory buffers all be used interchangeably.
  • io.EOF is the special error signaling that a Reader has no more data.
  • strings.NewReader and bytes.Buffer are common ways to get an io.Reader/io.Writer without real I/O.
🔒

Chapter Quiz — Complete all 7 topics to unlock

0/7 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.