Go: 标准库 io
最基础的 I/O 抽象层,核心作用是把"读、写"等能力统一成一组通用接口。
io 包定义了接口和组合方式,不负责具体实现。
核心接口
提供读、写、关闭、定位四个基础能力;这四个基础能力可以按需组合成更具体的接口
写数据
把w io.Writer看作数据目标,n, err = w.Write(p)表示把p里的数据写n个byte到w中
语义:流式生产,向当前位置顺序写;返回实际写入的字节数 n
// go doc io.Writer
type Writer interface {
Write(p []byte) (n int, err error)
}读数据
把r io.Reader看作数据源,n, err = r.Read(p)表示从数据源r中读取n个byte到缓存区p中;
语义:流式消费,从当前位置顺序读;最多读 len(p) 个字节,不保证读满,返回实际读到的字节数 n
// go doc io.Reader
type Reader interface {
Read(p []byte) (n int, err error)
}疑问:为什么不
Read() (p []byte, err error)?
回答:由调用方决定[]byte,方便复用,减少内存压力
关闭
// go doc io.Closer
type Closer interface {
Close() error
}定位
设置读/写操作的当前位置偏移量
// 第二个参数表示位置是开始/当前/末尾
// go doc io.Seeker
type Seeker interface {
Seek(offset int64, whence int) (int64, error)
}
// Seek whence values.
const (
SeekStart = 0 // seek relative to the origin of the file
SeekCurrent = 1 // seek relative to the current offset
SeekEnd = 2 // seek relative to the end
)一些变体(特殊语义)
数据搬运优化
谁来主导数据搬运,以及能不能走优化路径,比如 sendfile、splice、内部缓冲优化
// 目标端主动从源端r拉取数据
// go doc io.ReaderFrom
type ReaderFrom interface {
ReadFrom(r Reader) (n int64, err error)
}
// 源端主动向目标端w推数据
// go doc io.WriterTo
type WriterTo interface {
WriteTo(w Writer) (n int64, err error)
}src/os/zero_copy_linux.go:18 *os.File 实现的零拷贝优化
按位置访问
可按位置访问的数据空间
// go doc io.ReaderAt
type ReaderAt interface {
ReadAt(p []byte, off int64) (n int, err error)
}
// go doc io.WriterAt
type WriterAt interface {
WriteAt(p []byte, off int64) (n int, err error)
}适配器(组合)
把已有的 Reader/Writer 重新组合成新的行为
// 返回一个新的 Writer,写一次,相当于同时写多个目标
// go doc io.MultiWriter
func MultiWriter(writers ...Writer) Writer
// 返回一个新的 Reader,按顺序读多个输入源
// go doc io.MultiReader
func MultiReader(readers ...Reader) Reader
// 返回一个新的 Reader,读取时同时把读到的数据写进 w
// go doc io.TeeReader
func TeeReader(r Reader, w Writer) Reader
// 返回一个新的 Reader,但最多只能读 n 字节
// go doc io.LimitReader
func LimitReader(r Reader, n int64) Reader
// 返回一个新的 ReadCloser,Close() 是空实现
// go doc io.NopCloser
func NopCloser(r Reader) ReadCloser工具函数
- 读数据
// go doc io.ReadAll
func ReadAll(r Reader) ([]byte, error)
// 读入数据到buf,读满
func ReadFull(r Reader, buf []byte) (n int, err error)
// 读入数据到buf,读至少min个字节
func ReadAtLeast(r Reader, buf []byte, min int) (n int, err error)- 写数据
// go doc io.WriteString
func WriteString(w Writer, s string) (n int, err error)- 复制数据
// go doc io.Copy
// I/O 里最核心的"数据搬运调度器"
func Copy(dst Writer, src Reader) (written int64, err error)
// 只拷贝N个字节
func CopyN(dst Writer, src Reader, n int64) (written int64, err error)
// 缓存区caller提供
func CopyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error)- 管道
// go doc io.Pipe
// io.Pipe 是同步内存管道。没有内部 buffer。写端会阻塞,直到读端把这次写入的数据读走。
func Pipe() (*PipeReader, *PipeWriter)错误、值
# 正常读到结尾
go doc io.EOF
# 本来还该有数据,但提前结束
go doc io.ErrUnexpectedEOF
# 写入不完整
go doc io.ErrShortWrite
# 缓冲区太小
go doc io.ErrShortBuffer
# 对已关闭的管道读写
go doc io.ErrClosedPipe
# 多次 Read 都没有进展
go doc io.ErrNoProgress
# 值:类“黑洞”,写进去的数据直接丢弃
# var Discard Writer = discard{}
go doc io.Discard
评论