๐ŸŽ“ A1Learner
๐Ÿ”
0 of 28 lessons completed

Go IO Copiers

IO copiers are helpers that move bytes from a reader to a writer. io.Copy does the moving, and small wrapper readers change what flows through.

Copying a string into a buffer

io.Copy reads from a strings.Reader and writes into a bytes.Buffer. It also returns the count of bytes moved.

package main

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

func main() {
	var buf bytes.Buffer
	n, _ := io.Copy(&buf, strings.NewReader("copy me"))
	fmt.Println(buf.String())
	fmt.Println(n)
}

Capping a reader

io.LimitReader wraps the reader for abcdefgh with a limit of three. Reading it gives only the first three letters.

package main

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

func main() {
	r := io.LimitReader(strings.NewReader("abcdefgh"), 3)
	data, _ := io.ReadAll(r)
	fmt.Println(string(data))
}

Joining readers and saving a copy

io.MultiReader reads Go and then an exclamation mark as one stream. io.TeeReader passes the word flow on and saves the same bytes in a buffer.

package main

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

func main() {
	joined := io.MultiReader(strings.NewReader("Go"), strings.NewReader("!"))
	data, _ := io.ReadAll(joined)
	fmt.Println(string(data))
	var saved bytes.Buffer
	tee := io.TeeReader(strings.NewReader("flow"), &saved)
	out, _ := io.ReadAll(tee)
	fmt.Println(string(out), saved.String())
}

Example

package main

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

func main() {
	line := "trimming the log line"
	var saved bytes.Buffer
	tee := io.TeeReader(strings.NewReader(line), &saved)
	io.ReadAll(tee)
	limited := io.LimitReader(strings.NewReader(saved.String()), 5)
	trimmed, _ := io.ReadAll(limited)
	fmt.Println(string(trimmed))
	fmt.Println(saved.String())
}

Key points

  • Use io.Copy to move all bytes from a reader into a writer.
  • io.Copy returns the number of bytes it moved.
  • io.LimitReader wraps a reader and stops after a set number of bytes.
  • io.MultiReader joins readers so they read as one stream in order.
  • io.TeeReader writes a copy of every byte it passes on to a writer.

In this example, a TeeReader reads the whole line and saves a full copy in a buffer. A LimitReader then reads the saved text with a limit of five. Main prints the trimmed text first and the full copy second.

Note

The order of wrappers matters, because each wrapper changes the stream the next one sees.

Try it Yourself

Edit the code, then press Run.

Running is simulated ยท Go Playground

Exercise

What does io.LimitReader do to the stream it wraps?