io 套件定義了 Go 的 I/O 操作核心介面。Go 的 I/O 設計遵循「小介面」原則,透過組合這些基本介面,可以彈性描述各種 I/O 能力。

核心介面#

// 讀取介面
type Reader interface {
    Read(p []byte) (n int, err error)
}

// 寫入介面
type Writer interface {
    Write(p []byte) (n int, err error)
}

// 關閉介面
type Closer interface {
    Close() error
}

// 組合介面
type ReadWriter interface {
    Reader
    Writer
}

type ReadCloser interface {
    Reader
    Closer
}

type WriteCloser interface {
    Writer
    Closer
}

type ReadWriteCloser interface {
    Reader
    Writer
    Closer
}

io.Reader 詳解#

// Read 方法契約:
// - 讀取最多 len(p) 位元組到 p
// - 回傳讀取的位元組數 n(0 <= n <= len(p))
// - 到達結尾時回傳 n, io.EOF
// - 可能同時回傳資料和錯誤

func ReadAll(r io.Reader) ([]byte, error) {
    var result []byte
    buf := make([]byte, 1024)

    for {
        n, err := r.Read(buf)
        if n > 0 {
            result = append(result, buf[:n]...)
        }
        if err == io.EOF {
            break
        }
        if err != nil {
            return nil, err
        }
    }
    return result, nil
}
常見 io.Reader 實作
型別說明
*os.File檔案讀取
*strings.Reader從字串讀取
*bytes.Reader從位元組切片讀取
*bytes.Buffer從緩衝區讀取
net.Conn網路連線讀取
*http.Response.BodyHTTP 回應讀取
*gzip.Reader解壓縮讀取

io.Writer 詳解#

// Write 方法契約:
// - 把 p 中的資料寫入底層資料流
// - 回傳寫入的位元組數 n(0 <= n <= len(p))
// - 若 n < len(p),必須回傳非 nil 的錯誤

type UpperWriter struct {
    w io.Writer
}

func (u *UpperWriter) Write(p []byte) (int, error) {
    upper := bytes.ToUpper(p)
    return u.w.Write(upper)
}

// 使用
var buf bytes.Buffer
uw := &UpperWriter{w: &buf}
uw.Write([]byte("hello"))
fmt.Println(buf.String())  // "HELLO"

實用 I/O 函式#

import "io"

// 複製資料
n, err := io.Copy(dst, src)  // 完整複製
n, err := io.CopyN(dst, src, 1024)  // 複製 1024 位元組

// 讀取全部
data, err := io.ReadAll(reader)

// 寫入字串
n, err := io.WriteString(writer, "hello")

// 讀取指定數量
buf := make([]byte, 10)
n, err := io.ReadFull(reader, buf)  // 必須讀滿 10 位元組

// 限制讀取
limitedReader := io.LimitReader(reader, 1024)  // 最多讀 1024 位元組

// 多重讀取
tee := io.TeeReader(src, dst)  // 讀取的同時寫入 dst

io.Pipe#

建立同步的記憶體管道:

pr, pw := io.Pipe()

go func() {
    defer pw.Close()
    pw.Write([]byte("Hello from pipe"))
}()

data, _ := io.ReadAll(pr)
fmt.Println(string(data))  // "Hello from pipe"