io defines the Reader, Writer, and Closer interfaces every other I/O package builds on, plus a set of functions for copying, combining, and wrapping them without caring what's on the other end.
Examples
Copy reads src to EOF and writes everything to dst, returning the byte count it moved.
src := strings.NewReader("hello, io")
var dst bytes.Buffer
n, err := io.Copy(&dst, src)
fmt.Println(n, err)
fmt.Println(dst.String())9
hello, io TeeReader lets a single pass over src both consume the data and feed a second writer, here a hash, without buffering the whole thing twice.
src := strings.NewReader("hello, io")
h := sha256.New()
tee := io.TeeReader(src, h)
data, _ := io.ReadAll(tee)
fmt.Println(string(data))
fmt.Printf("%x\n", h.Sum(nil)[:6])hello, io
abfe060fc10cMultiWriter fans a single write out to several destinations at once. MultiReader does the opposite: it stitches several readers into one, exhausting each in order.
var a, b bytes.Buffer
w := io.MultiWriter(&a, &b)
io.WriteString(w, "logged twice")
fmt.Println(a.String())
fmt.Println(b.String())
r := io.MultiReader(strings.NewReader("foo-"), strings.NewReader("bar"))
data, _ := io.ReadAll(r)
fmt.Println(string(data))logged twice
logged twice
foo-barA SectionReader carves out a fixed window of an underlying ReaderAt. Read advances through that window; ReadAt jumps to any offset inside it without disturbing Read's own position.
base := strings.NewReader("0123456789abcdefghij")
sec := io.NewSectionReader(base, 5, 5)
fmt.Println(sec.Size())
buf := make([]byte, 5)
n, err := sec.Read(buf)
fmt.Println(n, err, string(buf[:n]))
b2 := make([]byte, 3)
n2, err2 := sec.ReadAt(b2, 1)
fmt.Println(n2, err2, string(b2[:n2]))5
5 56789
3 678 Pipe connects a Reader end to a Writer end with no buffer between them. The write has to happen on its own goroutine, since a Write blocks until a matching Read drains it.
r, w := io.Pipe()
go func() {
w.Write([]byte("streamed"))
w.Close()
}()
data, _ := io.ReadAll(r)
fmt.Println(string(data))streamedInterfaces, Functions & Types
| Function | Description |
|---|---|
EOF | Sentinel error returned by Read when no more input is available. |
ErrUnexpectedEOF | Returned when EOF arrives mid-structure, after some but not all of the expected data was read. |
ErrShortWrite | Returned when a write accepted fewer bytes than it was given, with no other explanation. |
ErrShortBuffer | Returned when a read needs a larger buffer than the one it was given. |
ErrClosedPipe | Returned by Pipe operations performed after the pipe has already been closed. |
ErrNoProgress | Returned by callers of ReadAtLeast-style loops after many consecutive reads return no data and no error. |
SeekStart | Seek whence value: offset is relative to the start of the file. |
SeekCurrent | Seek whence value: offset is relative to the current offset. |
SeekEnd | Seek whence value: offset is relative to the end. |
Discard | A Writer that discards everything written to it, like /dev/null. |
Reader1 method | The source half of the package. Anything bytes can be read from. |
Read(p []byte) (n int, err error) Fills as much of p as it can. Read n bytes out of p[:n]; n > 0 and a non-nil err can both happen on the same call. Implemented by *os.File, *strings.Reader, *bytes.Buffer, net.Conn, http.Request.Body, *gzip.Reader | |
Writer1 method | The destination half. Anything bytes can be written to. |
Write(p []byte) (n int, err error) Writes all of p, or returns an error saying why it could not. n < len(p) always comes with a non-nil err. Implemented by *os.File, *bytes.Buffer, *strings.Builder, net.Conn, http.ResponseWriter, io.Discard | |
Closer1 method | Anything holding a resource that has to be released. |
Close() error Releases the underlying resource. Calling it twice is not guaranteed to be safe; check the concrete type. Implemented by *os.File, net.Conn, http.Request.Body, *gzip.Writer | |
Seeker1 method | Anything with a cursor that can be moved. |
Seek(offset int64, whence int) (int64, error) Moves the cursor relative to SeekStart, SeekCurrent or SeekEnd, and reports the new absolute offset. Implemented by *os.File, *strings.Reader, *bytes.Reader | |
ReaderAt1 method | Reads from a fixed offset, leaving any cursor where it was. |
ReadAt(p []byte, off int64) (n int, err error) Safe to call concurrently from several goroutines, which is the point of it: no shared cursor to race over. Implemented by *os.File, *strings.Reader, *bytes.Reader | |
WriterAt1 method | Writes at a fixed offset, leaving any cursor where it was. |
WriteAt(p []byte, off int64) (n int, err error) Also safe to call concurrently, for the same reason. Implemented by *os.File | |
ReaderFrom1 method | A destination that knows how to pull from a source itself. |
ReadFrom(r Reader) (n int64, err error) io.Copy looks for this first and hands the whole transfer over, which is how a file copy can reach the kernel's sendfile instead of shuttling through a buffer. Implemented by *os.File, *bytes.Buffer, net.TCPConn | |
WriterTo1 method | A source that knows how to push itself to a destination. |
WriteTo(w Writer) (n int64, err error) The mirror of ReaderFrom, and the other shortcut io.Copy checks for before falling back to its own buffer. Implemented by *bytes.Buffer, *strings.Reader, *bytes.Reader | |
ByteReader1 method | Reads one byte at a time, without a slice. |
ReadByte() (byte, error) Returns io.EOF when there is nothing left. Parsers take this rather than Reader when they consume input one byte at a time. Implemented by *bufio.Reader, *bytes.Buffer, *strings.Reader | |
ByteScanner2 methods | A ByteReader that can put the last byte back. |
ReadByte() (byte, error) From ByteReader. UnreadByte() error Puts the last byte read back, so the next ReadByte returns it again. One byte of lookahead, which is what a hand-written parser usually needs. Implemented by *bufio.Reader, *bytes.Reader, *strings.Reader | |
ByteWriter1 method | Writes one byte at a time, without a slice. |
WriteByte(c byte) error No count to check: it either wrote the byte or returned an error. Implemented by *bufio.Writer, *bytes.Buffer, *strings.Builder | |
RuneReader1 method | Reads one UTF-8 character at a time. |
ReadRune() (r rune, size int, err error) size is how many bytes that character occupied, which is 1 for ASCII and up to 4 otherwise. Implemented by *bufio.Reader, *strings.Reader, *bytes.Reader | |
RuneScanner2 methods | A RuneReader that can put the last character back. |
ReadRune() (r rune, size int, err error) From RuneReader. UnreadRune() error Puts the last rune back. text/scanner and regexp both take this so they can look one character ahead and change their mind. Implemented by *bufio.Reader, *strings.Reader, *bytes.Reader | |
StringWriter1 method | Accepts a string directly, skipping the []byte conversion. |
WriteString(s string) (n int, err error) Converting a string to []byte copies it. A type implementing this can avoid that; io.WriteString checks for it and falls back to the conversion when it is absent. Implemented by *bufio.Writer, *strings.Builder, *bytes.Buffer, http.ResponseWriter | |
ReadWriter2 methods | Reader and Writer. |
Read(p []byte) (n int, err error) From Reader. Write(p []byte) (n int, err error) From Writer. Implemented by *os.File, net.Conn, *bytes.Buffer, *bufio.ReadWriter | |
ReadCloser2 methods | Reader and Closer. The shape of an HTTP request body. |
Read(p []byte) (n int, err error) From Reader. Close() error From Closer. An HTTP body must be closed even if you never read it. Implemented by http.Request.Body, http.Response.Body, *os.File, *gzip.Reader | |
WriteCloser2 methods | Writer and Closer. |
Write(p []byte) (n int, err error) From Writer. Close() error From Closer. For a compressor this is also what flushes the trailer, so skipping it truncates the output. Implemented by *os.File, *gzip.Writer, net.Conn | |
ReadWriteCloser3 methods | Reader, Writer and Closer. The shape of a network connection. |
Read(p []byte) (n int, err error) From Reader. Write(p []byte) (n int, err error) From Writer. Close() error From Closer. Implemented by *os.File, net.Conn | |
ReadSeeker2 methods | Reader and Seeker. What http.ServeContent wants. |
Read(p []byte) (n int, err error) From Reader. Seek(offset int64, whence int) (int64, error) From Seeker. Seeking is what lets a server answer a Range request without reading the whole file. Implemented by *os.File, *strings.Reader, *bytes.Reader | |
WriteSeeker2 methods | Writer and Seeker. |
Write(p []byte) (n int, err error) From Writer. Seek(offset int64, whence int) (int64, error) From Seeker. Implemented by *os.File | |
ReadWriteSeeker3 methods | Reader, Writer and Seeker. |
Read(p []byte) (n int, err error) From Reader. Write(p []byte) (n int, err error) From Writer. Seek(offset int64, whence int) (int64, error) From Seeker. Implemented by *os.File | |
ReadSeekCloser3 methods | Reader, Seeker and Closer. |
Read(p []byte) (n int, err error) From Reader. Seek(offset int64, whence int) (int64, error) From Seeker. Close() error From Closer. Implemented by *os.File | |
Copy(dst, src) (written int64, err error) io.Copy(&buf, r) // 9, nil | Copies from src to dst until EOF on src or an error. |
| |
CopyBuffer(dst, src, buf) (written int64, err error) | Like Copy, but uses the caller-supplied buffer instead of allocating one. |
| |
CopyN(dst, src, n) (written int64, err error) io.CopyN(&buf, r, 5) // 5, nil | Copies exactly n bytes from src to dst, or returns an error trying. |
ReadAll(r Reader) ([]byte, error) io.ReadAll(r) // []byte("hello"), nil | Reads from r until EOF and returns everything read; EOF itself is not reported as an error. |
ReadAtLeast(r, buf, min) (n int, err error) | Reads from r into buf until at least min bytes have arrived. |
| |
ReadFull(r Reader, buf []byte) (n int, err error) | Reads from r until buf is completely full. |
| |
WriteString(w Writer, s string) (n int, err error) io.WriteString(w, "hi") // 2, nil | Writes s to w, calling w's own WriteString method directly when w implements StringWriter. |
LimitReader(r Reader, n int64) Reader io.LimitReader(r, 3) | Returns a Reader that reads from r but reports EOF after n bytes. |
LimitedReader | The struct LimitReader returns: exported fields R Reader and N int64, the remaining byte budget. |
MultiReader(readers ...Reader) Reader io.MultiReader(r1, r2) // reads r1 fully, then r2 | Concatenates readers into one logical Reader, read in sequence. |
MultiWriter(writers ...Writer) Writer io.MultiWriter(w1, w2) | Duplicates every write across all of the given writers. |
TeeReader(r Reader, w Writer) Reader io.TeeReader(r, hasher) | Returns a Reader that also writes to w everything read from r, as it's read. |
NopCloser(r Reader) ReadCloser | Wraps r with a no-op Close method, for call sites that require a ReadCloser but need no real cleanup. |
OffsetWriter | A WriterAt that adds a fixed base offset to every WriteAt call. |
NewOffsetWriter(w WriterAt, off int64) *OffsetWriter | Constructs an OffsetWriter around w, starting at off. |
SectionReader | A ReadSeeker and ReaderAt limited to a fixed section of an underlying ReaderAt. |
NewSectionReader(r ReaderAt, off, n int64) *SectionReader io.NewSectionReader(r, 5, 5) | Constructs a SectionReader over n bytes of r starting at off. |
(*SectionReader) Read(p []byte) (n int, err error) | Reads within the section, advancing the section's own internal offset. |
(*SectionReader) ReadAt(p []byte, off int64) (n int, err error) | Reads at off relative to the section's start, ignoring and not advancing the internal offset. |
(*SectionReader) Seek(offset int64, whence int) (int64, error) | Moves the section's internal offset, bounded by the section's own start and length. |
(*SectionReader) Size() int64 | Returns the section's fixed length, exactly the n given to NewSectionReader. |
Pipe() (*PipeReader, *PipeWriter) | Creates an in-memory, synchronous pipe connecting a Reader end and a Writer end. |
| |
PipeReader | The read half of a Pipe; each Read blocks until a matching Write supplies data. |
PipeWriter | The write half of a Pipe; each Write blocks until a matching Read consumes it. |