【Golang 标准库】package io
io 包为 I/O 原语 (primitives) 提供了基本的接口。
Golang 的标准库中已经有很多 I/O 原语的具体实现,比如 os.File 的 Read 和 Write 方法。io 包的主要作用是抽象出这些实现的函数功能,并将其封装成公共的接口。
由于接口涉及的底层操作依赖具体实现,因此不应该假定接口中的方法是并发安全的。
在 io 包中最重要的是两个接口:Reader 和 Writer 接口,只要满足这两个接口,就可以使用 IO 包的功能。因此,Golang 中的很多 IO 包都跟这两个接口有关。
Part1 Reader
Reader 接口设计细节
1 | // io/io.go:77 |
细节 1
Read 函数将最多 len(p) 个字节读取到 p 中,并返回读取到的字节数 n(0 <= n <= len(p)) 和遇到的 err。
即使 Read 返回的 n < len(p),它也可能在调用过程中占用 len(p) 个字节作为暂存空间。
如果可读取的数据不足 len(p) 个字节,Read 一般会返回可用数据,而不会等待更多数据。
细节 2
当 Read 在成功读取 n > 0 个字节后遇到错误或 EOF,可以在本次调用返回一个 non-nil 错误。也可本次调用返回 nil,在下次调用再返回这个错误(且 n 为 0)。
例如当 n > 0 且读到输入末尾时,Read 可以返回 n, EOF 或 n, nil,并在下次调用 Read 时返回 0, EOF。但不建议在实现 Read 方法时返回 0, nil,开发者也不应该把 0, nil 当做 EOF 处理,除非 len(p)==0。
开发者在考虑 err 之前应该首先处理返回的 n > 0 个字节数据,这样可以正确应对成功读取若干个字节后遇到错误的情况,包括上文提到的 EOF 机制。
细节 3
所有实现都不应该保存切片 p。(Implementations must not retain p.)
Reader 接口的一些实现
实现 Reader 接口的常用类型有 os.File、strings.Reader、bufio.Reader、bytes.Buffer、bytes.Reader。
io 包本身的 LimitedReader、PipeReader、SectionReader 也实现了该接口。
下面,我们通过 ReadFrom 函数来了解该接口的具体用法。
1 | func ReadFrom(reader io.Reader, num int) ([]byte, error) { |
1 | // 从标准输入读取 |
os.Stdin
os.Stdin 是如何实现 Read 方法的呢?我们从源码中追溯一下。
1 | // os/file.go:63 |
可以看到,os.Stdin 其实是 os.File 类型,而该类型实现了 io.Reader 接口。
Part2 Writer
Writer 接口
1 | // Writer is the interface that wraps the basic Write method. |
Writer 接口的一些实现
fmt 包中,Fprint/Fprintf/Fprintln 接收一个 io.Writer 类型的参数,并把数据格式化输出到 io.Writer 中。
我们可以观察下标准库中是如何调用这些函数的。
1 | // fmt/print.go:262 |
os.Stdout 同样也是 os.File 类型,该类型也实现了 io.Writer 接口。
1 | // os/file.go:169 |

