io

Reader

type Reader interface {
    Read(p []byte) (n int, err error)
}

Reader只有一个Read方法,该方法从数据源中读取长度为len(p)的字节,存储到p中,返回读取的字节数和遇到的错误。

Writer

type Writer interface {
    Write(p []byte) (n int, err error)
}

Writer只有一个Write方法,该方法将p中的数据写入到数据流中,返回写入的字节数和遇到的错误。

Closer 和 Seeker

type Closer interface {
    Close() error
}

Closer接口封装了Close方法。

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

Seeker只有一个Seek方法,用于设置下一次读或写的偏移量。其中whence的取值:

  • 0:相对于头部
  • 1:相对于当前偏移量
  • 2:相对于尾部

组合接口

基于ReaderWriterCloserSeeker的组合,产生如下接口:

  • ReadWriter
  • ReadCloser
  • WriteCloser
  • ReadWriteCloser
  • ReadSeeker
  • WriteSeeker
  • ReadWriteSeeker

其它接口

ReaderFrom从一个Reader读取数据。

type ReaderFrom interface {
    ReadFrom(r Reader) (n int64, err error)
}

WriterTo将数据写入到一个Writer

type WriterTo interface {
    WriteTo(w Writer) (n int64, err error)
}

ReadAt从指定偏移量处开始读取数据。

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

WriterAt将数据写入到指定偏移量处。

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

ByteReader可以一次读取一个字节。

type ByteReader interface {
    ReadByte() (c byte, err error)
}

ByteScanner可以通过ReadByte方法读取一个字节,然后通过UnreadByte将读取的字节还原,这样下一次调用ReadByte的时候,读到的是相同的字节。

type ByteScanner interface {
    ByteReader
    UnreadByte() error
}

ByteWriter一次性写一个字节。

type ByteWriter interface {
    WriteByte(c byte) error
}

RuneReaderRuneScannerByteReaderByteScanner功能类似,不做赘述。

WriteString

首先定义了一个私有接口stringWriter

type stringWriter interface {
    WriteString(s string) (n int, err error)
}

然后:

func WriteString(w Writer, s string) (n int, err error) {
    // 如果w是一个stringWriter,即w有WriteString方法,则直接调用该方法
    if sw, ok := w.(stringWriter); ok {
        return sw.WriteString(s)
    }
    // 如果w不是stringWriter,则使用普通Writer的Write方法
    return w.Write([]byte(s))
}

ReadAtLeast 和 ReadFull

ReadAtLeast读取至少为min个字节到buf中:

func ReadAtLeast(r Reader, buf []byte, min int) (n int, err error) {
    // 源码比较简单,不做赘述
}

ReadFull读取恰好len(buf)个字节,实际上是调用了ReadAtLeast方法:

func ReadFull(r Reader, buf []byte) (n int, err error) {
    return ReadAtLeast(r, buf, len(buf))
}

Copy,CopyN,CopyBuffer

这几个方法最终依赖的都是一个私有方法copyBuffer,该方法会将一个输入流读到的数据写入到另一个输出流。

func copyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) {
    // 如果src实现了WriterTo接口,则直接使用其WriteTo方法
    if wt, ok := src.(WriterTo); ok {
        return wt.WriteTo(dst)
    }
    // 如果dst实现了ReaderFrom接口,则直接使用其ReadFrom方法
    if rt, ok := dst.(ReaderFrom); ok {
        return rt.ReadFrom(src)
    }
    // 分配buf,默认每次最多拷贝32K
    if buf == nil {
        buf = make([]byte, 32*1024)
    }
    for {
        nr, er := src.Read(buf)
        if nr > 0 {
            // 将读到的数据写入到输出流
            nw, ew := dst.Write(buf[0:nr])
            if nw > 0 {
                written += int64(nw)
            }
            // 写出错,退出
            if ew != nil {
                err = ew
                break
            }
            // 数据量不一致,报错退出
            if nr != nw {
                err = ErrShortWrite
                break
            }
        }
        // 拷贝完毕
        if er == EOF {
            break
        }
        // 出错退出
        if er != nil {
            err = er
            break
        }
    }
    return written, err
}

CopyBuffercopyBuffer基本一致,只不过需要预先分配缓冲区:

func CopyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) {
    if buf != nil && len(buf) == 0 {
        panic("empty buffer in io.CopyBuffer")
    }
    return copyBuffer(dst, src, buf)
}

Copy直接调用了copyBuffer,会使用默认大小的缓冲区:

func Copy(dst Writer, src Reader) (written int64, err error) {
    return copyBuffer(dst, src, nil)
}

CopyNCopy类似,只不过限定了拷贝的数据量。对数据量的限制是通过一个LimitedReader来实现的。

func CopyN(dst Writer, src Reader, n int64) (written int64, err error) {
    written, err = Copy(dst, LimitReader(src, n))
    if written == n {
        return n, nil
    }
    if written < n && err == nil {
        // src stopped early; must have been EOF.
        err = EOF
    }
    return
}

LimitedReader

LimitedReader是对Reader的一层包装,限制了最多读取的数据量。

type LimitedReader struct {
    R Reader // underlying reader
    N int64  // max bytes remaining
}

每次调用Read方法后,都会调整N的值:

func (l *LimitedReader) Read(p []byte) (n int, err error) {
    if l.N <= 0 {
        return 0, EOF
    }
    if int64(len(p)) > l.N {
        p = p[0:l.N]
    }
    n, err = l.R.Read(p)
    l.N -= int64(n) // 调整N的值
    return
}

LimitReader方法可以创建一个LimitedReader

func LimitReader(r Reader, n int64) Reader { return &LimitedReader{r, n} }