Go standard library defines several interfaces related to i/o.
They are crucial for abstracting i/o operation from the concrete object.
Thanks to io.Reader
interface we can write code that operates on any type that implements that interface, be it a type representing a file on disk, a network connection, or a buffer in memory.
Having, for example, a JSON decoder operate on io.Reader
is more powerful than JSON decoder that can only work on files.
For maximum flexibility, when possible you should write functions that operate on least specific interfaces like io.Reader
or io.Writer
and not concrete types like *os.File
.
io.Reader
type Reader interface {
Read(p []byte) (n int, err error)
}
io.Reader
is a crucial abstraction for reading from sequential stream of bytes.
Read
function reads up to len(p)
bytes into a buffer p
, returning the number of bytes read and error status.
It might return less than the len(p)
, even 0 bytes.
When it reaches end of file, it returns io.EOF
as error. Notice that Read
is allowed to return data in the same call as returning io.EOF
so handling end of file requires attention to details.
io.Reader
doesn’t allow going back in the stream. For that the type must implement io.Seeker
or io.ReaderAt
interfaces.
io.Writer
type Writer interface {
Write(p []byte) (n int, err error)
}
io.Writer
is for writing to a sequential stream of bytes.
Write
writes bytes in p
and returns the number of bytes written and error status.
Write
guarantees that it’ll write all data or return an error i.e. if returned n is < len(p) then err must be non-nil.
io.Closer
type Closer interface {
Close() error
}
Closer
describes streams that must be explicitly closed.