Skip to content

Go IO Package

The io package provides the fundamental building blocks for working with data streams. Almost everything in Go that reads or writes data (files, network connections, buffers) uses the interfaces defined here.

1. Core Interfaces

There are two primary interfaces you will see everywhere:

  • Reader: Anything that has a Read(p []byte) method. It fills the slice p with data.
  • Writer: Anything that has a Write(p []byte) method. It sends data from the slice p to a destination (like a file).
package main

import (
    "io"
    "os"
    "strings"
)

func main() {
    // 1. A Reader (strings.Reader)
    r := strings.NewReader("some data\n")

    // 2. A Writer (os.Stdout)
    w := os.Stdout

    // 3. io.Copy connects them together
    io.Copy(w, r)
}

2. Common Utility Functions

  • io.Copy(dst, src): Read everything from src and write it to dst until EOF.
  • io.ReadAll(r): Reads everything from a reader into a single []byte.
  • io.WriteString(w, s): A convenience function to write a string directly to a writer.

3. Combining Streams

  • io.MultiReader(r1, r2, ...): Combines multiple readers into one big reader that reads them in order.
  • io.MultiWriter(w1, w2, ...): A single writer that duplicates every write to multiple destinations (useful for logging to both terminal and file).
  • io.LimitReader(r, n): Reads at most n bytes from r.
  • io.TeeReader(r, w): Returns a reader that writes everything it reads to w (like the Unix tee command).

Why use io interfaces?

  1. Flexibility: You can write a function that takes an io.Reader, and it will work with files, HTTP bodies, ZIP archives, or plain strings without any changes.
  2. Efficiency: By using streams instead of loading everything into memory at once, your program can process gigabytes of data using only a few kilobytes of RAM.
  3. Standardization: Because the whole Go ecosystem uses these interfaces, libraries usually "just work" together.