Package io provides basic interfaces to I/O primitives. Its primary job is to wrap existing implementations of such primitives into shared public interfaces that abstract the functionality.
Core Interfaces
Reader
The interface that wraps the basic Read method.type Reader interface {
Read(p []byte) (n int, err error)
}
Read reads up to len(p) bytes into p. It returns the number of bytes read (0 ≤ n ≤ len(p)) and any error encountered. At end of file, Read returns 0, EOF.
Writer
The interface that wraps the basic Write method.type Writer interface {
Write(p []byte) (n int, err error)
}
Write writes len(p) bytes from p to the underlying data stream. It returns the number of bytes written and any error encountered.
Closer
The interface that wraps the basic Close method.type Closer interface {
Close() error
}
The behavior of Close after the first call is undefined.
Seeker
The interface that wraps the basic Seek method.type Seeker interface {
Seek(offset int64, whence int) (int64, error)
}
Seek sets the offset for the next Read or Write. Returns the new offset or an error.
Composite Interfaces
Groups the basic Read and Write methods.type ReadWriter interface {
Reader
Writer
}
Groups the basic Read and Close methods.type ReadCloser interface {
Reader
Closer
}
Groups the basic Write and Close methods.type WriteCloser interface {
Writer
Closer
}
Groups the basic Read, Write, and Close methods.type ReadWriteCloser interface {
Reader
Writer
Closer
}
Groups the basic Read and Seek methods.
Groups the basic Write and Seek methods.
Groups the basic Read, Write, and Seek methods.
Utility Functions
Copying Data
Copy
func Copy(dst Writer, src Reader) (written int64, err error)
Copies from src to dst until either EOF is reached on src or an error occurs. Returns the number of bytes copied and the first error encountered.written, err := io.Copy(dst, src)
CopyN
func CopyN(dst Writer, src Reader, n int64) (written int64, err error)
Copies n bytes from src to dst. Returns the number of bytes copied and the first error encountered.// Copy first 100 bytes
written, err := io.CopyN(dst, src, 100)
CopyBuffer
func CopyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error)
Identical to Copy but uses the provided buffer instead of allocating a temporary one.
Reading Data
ReadAll
func ReadAll(r Reader) ([]byte, error)
Reads from r until an error or EOF and returns the data read.data, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
ReadFull
func ReadFull(r Reader, buf []byte) (n int, err error)
Reads exactly len(buf) bytes from r into buf. Returns the number of bytes copied and an error if fewer bytes were read.buf := make([]byte, 100)
n, err := io.ReadFull(r, buf)
ReadAtLeast
func ReadAtLeast(r Reader, buf []byte, min int) (n int, err error)
Reads from r into buf until it has read at least min bytes. Returns the number of bytes copied and an error if fewer bytes were read.buf := make([]byte, 100)
n, err := io.ReadAtLeast(r, buf, 50) // Read at least 50 bytes
Writing Data
WriteString
func WriteString(w Writer, s string) (n int, err error)
Writes the contents of string s to w. If w implements a WriteString method, it is invoked directly.n, err := io.WriteString(w, "Hello, World!")
Helper Types
LimitReader
LimitReader
func LimitReader(r Reader, n int64) Reader
Returns a Reader that reads from r but stops with EOF after n bytes.// Read only first 1KB
limited := io.LimitReader(file, 1024)
data, err := io.ReadAll(limited)
MultiReader
MultiReader
func MultiReader(readers ...Reader) Reader
Returns a Reader that’s the logical concatenation of the provided readers.r1 := strings.NewReader("Hello ")
r2 := strings.NewReader("World")
r := io.MultiReader(r1, r2)
io.Copy(os.Stdout, r) // Hello World
MultiWriter
MultiWriter
func MultiWriter(writers ...Writer) Writer
Creates a writer that duplicates its writes to all provided writers.// Write to both file and stdout
w := io.MultiWriter(file, os.Stdout)
io.WriteString(w, "Hello")
TeeReader
TeeReader
func TeeReader(r Reader, w Writer) Reader
Returns a Reader that writes to w what it reads from r. All reads from r are written to w.// Read and log simultaneously
var buf bytes.Buffer
tee := io.TeeReader(resp.Body, &buf)
data, _ := io.ReadAll(tee)
log.Println("Read:", buf.String())
Pipe
Pipe
func Pipe() (*PipeReader, *PipeWriter)
Creates a synchronous in-memory pipe. Reads on the reader block until a write on the writer (or vice versa).r, w := io.Pipe()
go func() {
fmt.Fprintln(w, "Hello from pipe")
w.Close()
}()
io.Copy(os.Stdout, r)
Seek Constants
Seek relative to the origin of the file
Seek relative to the current offset
Seek relative to the end of the file
Common Errors
Error returned by Read when no more input is available. Functions should return EOF only to signal a graceful end of input.n, err := reader.Read(buf)
if err == io.EOF {
// End of input reached
}
Error indicating EOF was encountered in the middle of reading a fixed-size block or data structure.
Error indicating a write accepted fewer bytes than requested but failed to return an explicit error.
Error indicating a read required a longer buffer than was provided.
Examples
Reading from a File
package main
import (
"io"
"log"
"os"
)
func main() {
file, err := os.Open("example.txt")
if err != nil {
log.Fatal(err)
}
defer file.Close()
// Read all content
data, err := io.ReadAll(file)
if err != nil {
log.Fatal(err)
}
log.Printf("Read %d bytes\n", len(data))
}
Copying Files
package main
import (
"io"
"log"
"os"
)
func copyFile(src, dst string) error {
source, err := os.Open(src)
if err != nil {
return err
}
defer source.Close()
destination, err := os.Create(dst)
if err != nil {
return err
}
defer destination.Close()
_, err = io.Copy(destination, source)
return err
}
func main() {
err := copyFile("source.txt", "dest.txt")
if err != nil {
log.Fatal(err)
}
}
Using MultiWriter
package main
import (
"io"
"log"
"os"
)
func main() {
logFile, err := os.Create("app.log")
if err != nil {
log.Fatal(err)
}
defer logFile.Close()
// Write to both file and stdout
multi := io.MultiWriter(logFile, os.Stdout)
io.WriteString(multi, "Application started\n")
io.WriteString(multi, "Processing data\n")
}
Limited Reading
package main
import (
"io"
"log"
"strings"
)
func main() {
r := strings.NewReader("This is a long string with lots of content")
// Read only first 10 bytes
limited := io.LimitReader(r, 10)
data, err := io.ReadAll(limited)
if err != nil {
log.Fatal(err)
}
log.Printf("Read: %s\n", data) // "This is a "
}