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?