Skip to main content

Overview

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)
}
p
[]byte
required
Byte slice to read data into
n
int
Number of bytes read (0 to len(p))
err
error
Error encountered during read, or io.EOF at end
Example:
buf := make([]byte, 100)
n, err := reader.Read(buf)
if err != nil && err != io.EOF {
    log.Fatal(err)
}
fmt.Printf("Read %d bytes\n", n)

Writer

The interface that wraps the basic Write method.
type Writer interface {
    Write(p []byte) (n int, err error)
}
p
[]byte
required
Byte slice containing data to write
n
int
Number of bytes written from p (0 to len(p))
err
error
Error that caused the write to stop early
Example:
data := []byte("Hello, World!")
n, err := writer.Write(data)
if err != nil {
    log.Fatal(err)
}

Closer

The interface that wraps the basic Close method.
type Closer interface {
    Close() error
}
Example:
defer file.Close()

Seeker

The interface that wraps the basic Seek method.
type Seeker interface {
    Seek(offset int64, whence int) (int64, error)
}
offset
int64
required
Offset to seek to
whence
int
required
Reference point: SeekStart (0), SeekCurrent (1), or SeekEnd (2)
position
int64
New offset relative to start of file
err
error
Error encountered during seek
Example:
// Seek to beginning
file.Seek(0, io.SeekStart)

// Seek 10 bytes forward from current position
file.Seek(10, io.SeekCurrent)

// Seek to end
file.Seek(0, io.SeekEnd)

Composite Interfaces

ReadWriter

Groups the basic Read and Write methods.
type ReadWriter interface {
    Reader
    Writer
}

ReadCloser

Groups the basic Read and Close methods.
type ReadCloser interface {
    Reader
    Closer
}

WriteCloser

Groups the basic Write and Close methods.
type WriteCloser interface {
    Writer
    Closer
}

ReadWriteCloser

Groups Read, Write, and Close methods.
type ReadWriteCloser interface {
    Reader
    Writer
    Closer
}

ReadSeeker

Groups the basic Read and Seek methods.
type ReadSeeker interface {
    Reader
    Seeker
}

Utility Functions

Copy

Copies from src to dst until EOF or error.
func Copy(dst Writer, src Reader) (written int64, err error)
dst
Writer
required
Destination to write to
src
Reader
required
Source to read from
written
int64
Number of bytes copied
err
error
First error encountered while copying, if any
Example:
src, _ := os.Open("source.txt")
dst, _ := os.Create("dest.txt")
defer src.Close()
defer dst.Close()

written, err := io.Copy(dst, src)
if err != nil {
    log.Fatal(err)
}
fmt.Printf("Copied %d bytes\n", written)

CopyN

Copies n bytes (or until an error) from src to dst.
func CopyN(dst Writer, src Reader, n int64) (written int64, err error)
dst
Writer
required
Destination writer
src
Reader
required
Source reader
n
int64
required
Number of bytes to copy
Example:
// Copy first 100 bytes
written, err := io.CopyN(dst, src, 100)

ReadAll

Reads from r until an error or EOF and returns the data it read.
func ReadAll(r Reader) ([]byte, error)
r
Reader
required
Reader to read all data from
data
[]byte
All data read from the reader
err
error
Error encountered (EOF is not treated as an error)
Example:
data, err := io.ReadAll(reader)
if err != nil {
    log.Fatal(err)
}
fmt.Printf("Read %d bytes\n", len(data))

ReadFull

Reads exactly len(buf) bytes from r into buf.
func ReadFull(r Reader, buf []byte) (n int, err error)
r
Reader
required
Reader to read from
buf
[]byte
required
Buffer to fill completely
Example:
buf := make([]byte, 100)
n, err := io.ReadFull(reader, buf)
if err != nil {
    log.Fatal(err)
}
// buf is now completely filled

ReadAtLeast

Reads from r into buf until it has read at least min bytes.
func ReadAtLeast(r Reader, buf []byte, min int) (n int, err error)
r
Reader
required
Reader to read from
buf
[]byte
required
Buffer to read into
min
int
required
Minimum number of bytes to read

WriteString

Writes the contents of string s to w.
func WriteString(w Writer, s string) (n int, err error)
w
Writer
required
Writer to write to
s
string
required
String to write
Example:
n, err := io.WriteString(writer, "Hello, World!")

Special Readers and Writers

LimitReader

Returns a Reader that reads from r but stops with EOF after n bytes.
func LimitReader(r Reader, n int64) Reader
r
Reader
required
Underlying reader
n
int64
required
Maximum number of bytes to read
Example:
// Read at most 100 bytes
limited := io.LimitReader(file, 100)
data, _ := io.ReadAll(limited)

TeeReader

Returns a Reader that writes to w what it reads from r.
func TeeReader(r Reader, w Writer) Reader
r
Reader
required
Reader to read from
w
Writer
required
Writer to copy data to
Example:
var buf bytes.Buffer
tee := io.TeeReader(file, &buf)
io.ReadAll(tee) // Reads from file and writes to buf

NopCloser

Returns a ReadCloser with a no-op Close method wrapping the provided Reader.
func NopCloser(r Reader) ReadCloser
Example:
rc := io.NopCloser(strings.NewReader("data"))
defer rc.Close() // Close does nothing but satisfies interface

Variables

EOF

The error returned by Read when no more input is available.
var EOF = errors.New("EOF")
Example:
n, err := reader.Read(buf)
if err == io.EOF {
    fmt.Println("Reached end of file")
}

ErrUnexpectedEOF

Means that EOF was encountered in the middle of reading a fixed-size block or data structure.
var ErrUnexpectedEOF = errors.New("unexpected EOF")

ErrShortWrite

Means that a write accepted fewer bytes than requested but failed to return an explicit error.
var ErrShortWrite = errors.New("short write")

ErrShortBuffer

Means that a read required a longer buffer than was provided.
var ErrShortBuffer = errors.New("short buffer")

Discard

A Writer on which all Write calls succeed without doing anything.
var Discard Writer = discard{}
Example:
// Discard all output
io.Copy(io.Discard, reader)

Complete Example

package main

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

func main() {
    // Reading from a string
    reader := strings.NewReader("Hello, World!")
    
    // Copy to stdout
    io.Copy(os.Stdout, reader)
    fmt.Println()
    
    // Read with limit
    reader = strings.NewReader("0123456789")
    limited := io.LimitReader(reader, 5)
    data, _ := io.ReadAll(limited)
    fmt.Printf("Limited read: %s\n", data) // Output: 01234
    
    // Tee reader
    var buf strings.Builder
    reader = strings.NewReader("test")
    tee := io.TeeReader(reader, &buf)
    io.Copy(io.Discard, tee)
    fmt.Printf("Tee captured: %s\n", buf.String())
}

Build docs developers (and LLMs) love