Reference material. Each interface listed with method signature, preconditions, postconditions, and invariants. Sentinel-error tables follow the interface tables. Concurrency table at the end.
This file is a distillation of the io, os, io/fs, and bufio package documentation as of Go 1.22, with implementation notes that the docs leave implicit. For prose explanations, see senior.md. For production patterns, see professional.md.
MAY use all of p (including p[n:]) as scratch space
EOF with data
MAY return (n > 0, io.EOF) in a single call
EOF after data
MAY return data first, then (0, io.EOF) on the next call
Zero/nil return
SHOULD NOT return (0, nil) except when len(p) == 0
Buffer retention
MUST NOT retain p after Read returns
Caller obligation
MUST process n > 0 bytes before considering err
len(p) == 0
Implementation-defined; usually returns (0, nil)
Errors other than io.EOF are reader-defined. io.ErrUnexpectedEOF is not returned by Read directly — it is generated by helpers (io.ReadFull, io.ReadAtLeast) when a Reader ends prematurely.
Caller pattern: retry with p[n:] until empty or error
len(p) == 0
Implementation-defined; usually returns (0, nil)
io.ErrShortWrite is the conventional error for "I tried to write all of p but only n < len(p) bytes made it." Callers see it from io.Copy-like helpers; primitives raise their own errors.
Behavior is undefined (most stdlib types return os.ErrClosed)
Error meaning on writers
A non-nil error means buffered/in-flight data may not have reached the destination
Error meaning on readers
Usually informational; data already returned remains valid
A reader's Close releases its hold on the source; a writer's Close finalizes the destination. For composed writers (gzip, bufio), Close also writes any pending trailer or buffered data and is therefore a correctness concern, not just resource cleanup.
Optional companion to Writer. io.WriteString(w, s) checks for it and falls back to w.Write([]byte(s)) if absent. Implementing it saves one allocation per call when the source is already a string.
The compositions below are pure interface combinations. They contain no methods of their own; the named methods are only those from the embedded interfaces.
Composite
Embeds
io.ReadCloser
Reader, Closer
io.WriteCloser
Writer, Closer
io.ReadWriteCloser
Reader, Writer, Closer
io.ReadSeeker
Reader, Seeker
io.WriteSeeker
Writer, Seeker
io.ReadWriteSeeker
Reader, Writer, Seeker
io.ReadSeekCloser
Reader, Seeker, Closer
io.ReadWriter
Reader, Writer
Naming convention: alphabetical order of method names.
Use errors.Is(err, io.EOF) rather than err == io.EOF. Some readers wrap the sentinel (e.g., decompressors may produce *gzip.Error{Err: io.ErrUnexpectedEOF}).
Returns io.EOF, or whatever was passed to CloseWithError
Write after reader Close
Returns io.ErrClosedPipe, or CloseWithError's value
Multiple writers
Each Write is delivered atomically; no interleaving guarantee on splits
Multiple readers
Each Read gets some bytes; other readers may starve
CloseWithError(nil)
Equivalent to Close() (yields io.EOF on the read side)
The "one writer, one reader" recommendation is operational, not contractual — multiple writers/readers don't corrupt memory, but ordering becomes nondeterministic.
Buffers; uses WriteString on underlying if available
No
Flush()
Writes buffered data to underlying writer
No
Available()
Bytes free in buffer
No
Buffered()
Bytes currently buffered
No
Reset(w)
Reset to wrap a different writer, reuse buffer
No
ReadFrom(r)
Copies from r until EOF, bypassing buffer for large reads
No
Flush is mandatory before Close of the underlying writer. bufio.Writer has no Close method — it relies on the caller to flush and close the underlying stream in the right order.
Slice for the current token; invalid after next Scan
Text()
String copy of Bytes()
Err()
First non-EOF error from scanning, or nil
Buffer(buf, max)
Set initial buffer and max token size
Split(SplitFunc)
Set the split function
Split function
Token shape
bufio.ScanBytes
One byte at a time
bufio.ScanRunes
One UTF-8 rune at a time
bufio.ScanWords
Whitespace-separated tokens
bufio.ScanLines
Lines, with trailing \r\n or \n stripped
Default MaxScanTokenSize is 65536. A token larger than this without calling Buffer results in bufio.ErrTooLong, and the token is lost (the scanner advances past it).
filepath.Clean removes ./.. syntactically; it does NOT prevent traversal because .. after a symlink is filesystem-resolved differently. Use filepath.EvalSymlinks plus a containment check, or os.Root (Go 1.24+).