I/O related interfaces

suggest change

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.


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.


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.


type Closer interface {
        Close() error

Closer describes streams that must be explicitly closed.

Close returns an error because it’s required in some real-world cases. For example, when doing buffered writes to a file, Close might need to flush remaining buffered data to a file, which might fail.

For that reason it’s important to check error returned from Close when closing a write-able streams.


type ReaderAt interface {
        ReadAt(p []byte, off int64) (n int, err error)

io.ReaderAt is like io.Reader but allows to read at any position in the stream.

This is possible in files but not in network connections.


type WriterAt interface {
        WriteAt(p []byte, off int64) (n int, err error)

io.WriterAt is like io.Write but allows to write at an arbitrary position in the stream.


type Seeker interface {
        Seek(offset int64, whence int) (int64, error)

io.Seeker allows seeking within the stream. If you can seek, you can also implement io.ReaderAt and io.WriterAt.

Feedback about page:

Optional: your email if you want me to get back to you:

Table Of Contents