概述
io 包提供了基本的 I/O 原语接口。它主要用于将类似 os 包中的已有 I/O 原语实现封装进公共抽象接口中,还附加了一些其他相关原语。
因为这些接口和原语封装了多个底层实现,如果没有特殊的说明,用户不能认为是并发安全的。
索引
- Constants
- func Copy(dst Writer, src Reader) (written int64, err error)
- func CopyN(dst Writer, src Reader, n int64) (written int64, err error)
- func ReadFull(r Reader, buf []byte) (n int, err error)
- type ByteReader
- type ByteWriter
- type LimitedReader
- type PipeReader
- type ReadSeeker
- type ReadWriteSeeker
- type Reader
- type ReaderAt
- type RuneReader
- type SectionReader
- type Seeker
- type WriteSeeker
- type WriterTo
文件
常量
表示从哪里开始查找的一系列常量。
变量
- var EOF = errors.("EOF")
当没有更多数据可以被读取的时候将会返回 EOF 错误。EOF 只应该在成功读取所有的输入数据后返回。如果在读取结构化数据流中意外的发生了 EOF,那么可以选择返回 ErrUnexpectedEOF 或者其他错误来提供更多的错误信息。
- var ErrClosedPipe = errors.("io: read/write on closed pipe")
当我们对一个已关闭的 pipe 读或写,会返回 ErrClosedPipe。
- var ErrNoProgress = errors.("multiple Read calls return no data or error")
当用户多次调用 io.Reader,既不返回错误也不返回数据,返回 ErrNoProgress。这通常意味着 io.Reader 接口的实现因为某种原因导致崩溃。
- var ErrShortBuffer = errors.("short buffer")
当读操作需要一个更大的缓存时,返回 ErrShortBuffer。
- var ErrShortWrite = errors.("short write")
当写入的字节少于最低需要的字符但是没有返回错误时,返回 ErrShortWrite。
- var ErrUnexpectedEOF = errors.("unexpected EOF")
当读取一个固定的数据块或者数据结构时遇到 EOF,返回 ErrUnexpectedEOF。
func Copy
Copy 方法将从 src 读取,直到遇见 EOF 或者发生错误,然后将读取到的数据写入 dst。它返回已经拷贝成功的字节数和第一个遇到的错误。
如果拷贝成功应该返回 err == nil, 而不是 err == EOF。因为拷贝的定义就是读取 src 直到遇见 EOF,它在读取到 EOF 时不应当将其视作一个错误。
如果 src 实现了 WriterTo 接口,拷贝操作将会调用 src.WriteTo(dst)。
如果 dst 实现了 ReaderFrom 接口,那么拷贝操作将会调用 dst.ReadFrom(src)。
r := strings.NewReader("some io.Reader stream to be read\n")
if _, err := io.Copy(os.Stdout, r); err != nil {
log.Fatal(err)
}
// Output:
// some io.Reader stream to be read
func
¶
CopyBuffer 和 Copy 很相似,唯一的区别就是它使用用户提供的缓存进行拷贝,而不是使用临时的缓存。如果 buf 是 nil,那么将会为其分配一个缓存,如果缓存的长度为 0,那么 CopyBuffer 将会 panic。
r1 := strings.NewReader("first reader\n")
r2 := strings.NewReader("second reader\n")
buf := make([]byte, 8)
// buf is used here...
if _, err := io.CopyBuffer(os.Stdout, r1, buf); err != nil {
log.Fatal(err)
}
// ... reused here also. No need to allocate an extra buffer.
if _, err := io.CopyBuffer(os.Stdout, r2, buf); err != nil {
log.Fatal(err)
}
// Output:
// first reader
// second reader
func
¶
CopyN 从 src 拷贝 n 字节到 dst,它返回拷贝的字节数和遇到的第一个错误。只当 err == nil 时,才会 n == written。
如果 dst 实现了 ReaderFrom 接口,那么拷贝将会使用 ReaderFrom 接口。
r := strings.NewReader("some io.Reader stream to be read")
if _, err := io.CopyN(os.Stdout, r, 5); err != nil {
log.Fatal(err)
}
// Output:
// some
func
¶
ReadAtLeast 从 r 至少读取 min 个字节到 buf 中。它返回成功拷贝的字节数,并且在字节数没有达到最小值时,返回一个错误。只有当没有字节可以读取的时候才返回 EOF。如果读取了小于 min 个字节后产生 EOF 错误。那么 ReadAtLeast 将返回 ErrUnexpectedEOF。如果 min 大于 buf 的长度,ReaderAtLeast 将返回 ErrShortBuffer。只有当 err == nil 的时候才会返回 n >= min。
r := strings.NewReader("some io.Reader stream to be read\n")
buf := make([]byte, 33)
if _, err := io.ReadAtLeast(r, buf, 4); err != nil {
log.Fatal(err)
fmt.Printf("%s\n", buf)
// buffer smaller than minimal read size.
shortBuf := make([]byte, 3)
if _, err := io.ReadAtLeast(r, shortBuf, 4); err != nil {
fmt.Println("error:", err)
}
// minimal read size bigger than io.Reader stream
longBuf := make([]byte, 64)
if _, err := io.ReadAtLeast(r, longBuf, 64); err != nil {
fmt.Println("error:", err)
}
// Output:
// some io.Reader stream to be read
// error: short buffer
// error: EOF
func
¶
ReadFull 从 r 读取 len(buf) 个字节到 buf。它返回拷贝的字节数,而当读取少于指定字节时,返回一个错误。只有没有字节可以读取的时候才会返回 EOF。如果一个 EOF 不是在读取最后一个字节后产生的,那么应该返回 ErrUnexpectedEOF。只有当 err == nil 的时候才会返回 n == len(buf)。
例:
r := strings.NewReader("some io.Reader stream to be read\n")
buf := make([]byte, 4)
if _, err := io.ReadFull(r, buf); err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", buf)
// minimal read size bigger than io.Reader stream
longBuf := make([]byte, 64)
if _, err := io.ReadFull(r, longBuf); err != nil {
fmt.Println("error:", err)
}
// Output:
// some
// error: unexpected EOF
func WriteString
WriteString 会将字符串 s 写入 w。如果 w 实现了 WriteString 方法。它将会被直接调用,否则会调用一次 w.Write。
io.WriteString(os.Stdout, "Hello World")
// Output: Hello World
type
¶
- type ByteReader interface {
- ReadByte() (, error)
- }
ByteReader 声明了 ReadByte 方法。
ReadByte 返回输入流中返回下一个字节和错误。如果 ReadByte 返回一个错误,输入流中的字符将不会被使用,并且返回字节的值也是未定义的。
- type ByteScanner interface {
- UnreadByte() error
- }
ByteScanner 为 ReadByte 方法添加对应的 UnreadByte 方法。
UnreadByte 将会使下一次的 ReadByte 调用返回与之前调用相同的字节。如果在两个 ReadByte 之间调用 UnreadByte 两次有可能发生错误。
type
¶
- type ByteWriter interface {
- WriteByte(c ) error
- }
ByteWriter 接口声明了 WriteByte 方法。
type
¶
Closer 接口声明了核心的 Close 方法。
如果先调用 Close 方法发生的行为是未定义的。具体实现可能会说明他们自己的函数行为。
type
¶
- type LimitedReader struct {
- R // underlying reader
- N int64 // max bytes remaining
- }
一个 LimitedReader 只从 R 中读取 N 字节。为了不断获取新的数据,每次读取都会更新 N 的值。当 N <= 0 时或者读取 R 时到了 EOF,函数会返回 EOF。
func (*LimitedReader)
¶
type
¶
- type PipeReader struct {
- // contains filtered or unexported fields
- }
PipeReader 是管道的读取端。
func
¶
- func Pipe() (*, *PipeWriter)
Pipe 创建一个同步的内存管道。它能够用来连接代码中需要 io.Reader 接口和 io.Wrtier 接口的部分。
在管道中,读取和写入是一一对应的,除了多个读取消耗单个写入的情况。所以写操作将会一直阻塞到有一个或多个读操作将写的内容全部接收。管道没有缓存,数据会直接从写入端拷贝到对应的读入端。
func (*PipeReader)
¶
- func (r *) Close() error
Close 会关闭管道的读取端。随后的写入操作将会返回 ErrClosedPipe 错误。
func (*PipeReader)
¶
- func (r *) CloseWithError(err error)
CloseWithError 会关闭读取端。写入端将会返回 err 错误。
- func (r *PipeReader) Read(data []) (n int, err )
Read 方法实现了标准的 Read 接口:它会从管道中读取数据,并且阻塞到有新数据被写入或者写入端被关闭。如果写入端发生错误而关闭,那么这个错误将会被返回给调用者,否则将返回 EOF。
type PipeWriter
- type PipeWriter struct {
- // contains filtered or unexported fields
- }
PipeWriter 是管道的写入端。
func (*PipeWriter) Close
- func (w *PipeWriter) Close()
Close 会关闭写入端。对管道的读操作将会返回 0 字节和 EOF。
func (*PipeWriter) CloseWithError
- func (w *PipeWriter) CloseWithError(err ) error
CloseWithError 会关闭写入端。如果设置了错误信息,那么管道的读取端随后的读操作将会获取到这个错误信息,如果错误信息是 nil。那么读取端将会返回 EOF。
CloseWithError 总是返回 nil。
func (*PipeWriter)
¶
Write 方法实现了标准的 Write 接口:它将数据写入管道然后一直阻塞到一个或多个 reader 读取到所有的数据,或者读取端被关闭。如果读操作发生错误导致关闭,那么这个错误将会被返回给调用者。否则将会返回 ERRClosedPipe 错误。
type
¶
- type ReadCloser interface {
- Closer
- }
ReadCloser 接口组合了 Read 和 Close 方法。
type
¶
- type ReadSeeker interface {
- Seeker
- }
ReadSeeker 接口组合了 Read 和 Seek 方法。
type
¶
- type ReadWriteCloser interface {
- Writer
- }
ReadWriteCloser 接口组合了 Read、Write 和 Close 方法。
type ReadWriteSeeker
ReadWriteSeeker 接口组合了 Read、Write 和 Seek 方法。
type
¶
- type ReadWriter interface {
- Writer
- }
ReadWriter 接口组合了 Read 和 Write 方法。
type
¶
- type Reader interface {
- Read(p []) (n int, err )
- }
Reader 接口声明了基本的 Read 方法。
Read 方法最多读取 len(p) 个字节并保存在切片 p 中。返回值有 2 个。n 代表成功读取的字节数,err 代表读取过程中发生的错误。即使读取操作返回的 n < len(p),它也会将 p 全部用于暂存空间。如果成功读取的数据不够 len(p) 个字节,Read 方法会直接返回读取成功的数据,而不会阻塞等待更多数据。
当 Read 方法发生了错误或者成功读取数据并到达文件末尾的时候,他将返回读成功读取到的字节数。这时可以在此次调用 Read 时返回非 nil 的错误或者在下次调用 Read 的时候返回这个错误并且返回 n == 0。一个这种情况的例子:当 Reader 成功读取到数据并且到达文件末尾的时候,可以在本次调用时返回 err == nil 或者 err == EOF。下一次调用应该返回 0,EOF。
调用者应该优先处理 n > 0 时的错误。这样做可以正确的处理那些读取到一半发生的错误,和 2 个允许返回 EOF 的情况。
Read 的实现不推荐同时返回 0 和 err == nil,除了 len(p) == 0 的情况。调用者应该把返回值为 0 和 nil 的情况看作什么也没发生,而不是 EOF。
Reader 的实现不能保存 p。
func LimitReader
LimitReader 返回一个从 r 中读取 n 个字符后返回 EOF 的 Reader。
底层的实现是 *LimitedReader。
例:
r := strings.NewReader("some io.Reader stream to be read\n")
lr := io.LimitReader(r, 4)
if _, err := io.Copy(os.Stdout, lr); err != nil {
log.Fatal(err)
}
// Output:
// some
func MultiReader
- func MultiReader(readers ...Reader)
MultiReader 返回一个逻辑上连接多个 Reader 的 Reader。它们会依次被读取。只有在所有的输入端全部返回 EOF 的时候,Read 才会返回 EOF。如果在这当中任何一个 Reader 返回了一个非 nil,非 EOF 的错误,那么这个错误都将被返回。
r1 := strings.NewReader("first reader ")
r2 := strings.NewReader("second reader ")
r3 := strings.NewReader("third reader\n")
r := io.MultiReader(r1, r2, r3)
if _, err := io.Copy(os.Stdout, r); err != nil {
log.Fatal(err)
}
// Output:
TeeReader 返回一个将所有从 r 中读取到的数据全部写入进 w 中的 Reader。
所有对 r 的读取操作都会对应将数据写入 w 的操作。它的内部没有缓冲机制,使用读取操作时必须等待内部写入 w 的操作完成后才能返回,所有写操作时的错误都会被作为读取操作的错误返回。
例:
r := strings.NewReader("some io.Reader stream to be read\n")
var buf bytes.Buffer
tee := io.TeeReader(r, &buf)
printall := func(r io.Reader) {
b, err := ioutil.ReadAll(r)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s", b)
}
printall(&buf)
// Output:
// some io.Reader stream to be read
// some io.Reader stream to be read
ReaderAt 接口声明了 ReadAt 方法。
ReadAt 从输入源根据 off 指定的偏移量开始将 len(p) 字节读入 p。他会返回成功读取的字节数(0 <= n <= len(p))和读取过程中发生的任何错误。
当 ReadAt 返回 n < len(p) 的时候,将会返回一个 非 nil 的错误来解释为什么其他的字节没有被读取。在这方面 ReadAt 比 Read 更加严格。
即使 ReadAt 返回了 n < len(p),它也可能会将 p 的所有元素用作暂存空间。如果成功读取的数据不能填满 p,那么 ReadAt 函数将会一直阻塞直到 p 被填满或者发生错误。在这方面 ReadAt 和 Read 是不同的。
如果 ReadAt 在读取 n = len(p) 后正好到达输入数据的末尾,ReadAt 可以选择返回 err == EOF 或者 err == nil 都可以。
如果 ReadAt 在一个已经拥有偏移量的输入数据上读取,那么 ReadAt 不能影响数据源原本的偏移量。
ReadAt 的实现不能保存 p。
type ReaderFrom
ReaderFrom 接口声明了 ReadFrom 方法。
ReadFrom 从 r 中读取数据直到读取到 EOF 或者发生的错误。
返回值 n 是成功读取到的字节数。除了 io.EOF 任何读取时发生的错误都会被返回。
如果 Copy 的 dst 实现了 ReaderFrom 接口。那么 ReadFrom 会被 Copy 函数调用。
type
¶
- type RuneReader interface {
- ReadRune() (r , size int, err )
- }
RuneReader 接口声明了 ReadRune 方法。
ReadRune 会读取一个 UTF-8 编码的字符并且返回这个字符和他的字节数。如果没有合法的字符,将会返回错误。
type RuneScanner
- type RuneScanner interface {
- RuneReader
- UnreadRune()
- }
RunScanner 接口为 ReadRune 方法添加对应的 UnreadRune 方法。
UnreadRune 会让下一次调用 ReadRune 和之前返回相同的值。如果在 ReadRune 调用的间隔中连续调用 2 次 UnreadRune 可能会发生错误。
type SectionReader
- type SectionReader struct {
- // contains filtered or unexported fields
- }
SectionReader 在 ReaderAt 获取到的数据片段上实现了 Read、Seek 和 ReadAt 接口。
r := strings.NewReader("some io.Reader stream to be read\n")
s := io.NewSectionReader(r, 5, 17)
if _, err := io.Copy(os.Stdout, s); err != nil {
log.Fatal(err)
}
// Output:
// io.Reader stream
func
¶
- func NewSectionReader(r , off int64, n ) *SectionReader
NewSectionReader 返回一个 SectionReader,它能读取 r 中以 off 作为偏移量以后的 n 个字节的数据,返回的 Reader 在读取完第 n 个字节后返回 EOF。
func (*SectionReader)
¶
func (*SectionReader)
¶
r := strings.NewReader("some io.Reader stream to be read\n")
s := io.NewSectionReader(r, 5, 16)
buf := make([]byte, 6)
if _, err := s.ReadAt(buf, 10); err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", buf)
// Output:
// stream
func (*SectionReader)
¶
r := strings.NewReader("some io.Reader stream to be read\n")
s := io.NewSectionReader(r, 5, 16)
if _, err := s.Seek(10, io.SeekStart); err != nil {
log.Fatal(err)
}
buf := make([]byte, 6)
if _, err := s.Read(buf); err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", buf)
// Output:
// stream
func (*SectionReader)
¶
- func (s *) Size() int64
Size 返回 SectionReader 中的字节数。
type
¶
Seeker 接口声明了 Seek 方法。
Seek 方法设置了下一次读或写的偏移位置。根据 whence 参数的 3 种情况:
- SeekStart 表示从文件开始处进行偏移。
- SeekCurrent 表示从当前位置进行偏移。
- SeekEnd 表示从文件末尾进行偏移。
Seek 返回相对于文件开始处的偏移量,如果发生了错误,也会返回错误。
偏移到超前于文件开始处的位置将会返回一个错误。一个正向偏移永远是合法的,但是在随后的 I/O 操作的行为依赖于具体实现。
type
¶
- type WriteCloser interface {
- Closer
- }
WriteCloser 接口组合了 Write 和 Close 方法。
type
¶
- type WriteSeeker interface {
- Seeker
- }
WriteSeeker 接口组合了 Write 和 Seek 方法。
type
¶
- type Writer interface {
- Write(p []) (n int, err )
- }
Writer 接口声明了 Write 方法。
Write 方法将 p 中的所有元素写入底层数据流。并且返回成功写入 p 中的字节数和在写入过程中引起写入失败的错误。如果 Write 方法返回的 n < len(p),那么它必须返回一个非 nil 的错误。Write 方法不能修改切片中的数据,即使这个切片中的数据是暂时的。
实现不能保留切片 p。
- func MultiWriter(writers ...Writer)
MultiWriter 会创建一个将写入的字符复制给每个 Writer 的 Wrtier。与 Unix 下的 tee(1) 命令相似。
r := strings.NewReader("some io.Reader stream to be read\n")
var buf1, buf2 bytes.Buffer
w := io.MultiWriter(&buf1, &buf2)
if _, err := io.Copy(w, r); err != nil {
log.Fatal(err)
}
fmt.Print(buf1.String())
fmt.Print(buf2.String())
// Output:
// some io.Reader stream to be read
type
¶
WriteAt 接口声明了基本的 WriteAt 方法。
WriteAt 将 p 中的 len(p) 个字节写入到数据流偏移量 off 的位置。它返回从 p 中成功写入的字节数 (0 <= n <= len(p)) 和写入过程中发生的任何使写入过早中断的错误。WriteAt 在返回的 n < len(p) 时必须返回一个非 nil 的错误。
如果 WriteAt 执行在一个带有偏移量的数据流上,WriteAt 不应该影响底层数据流原本的偏移量。
只要写入的区域没有重叠,我们就可以并发的调用 WriteTo 方法。
所有该接口的实现都不能保留 p。
type
¶
WriterTo 接口声明了 WriteTo 方法。
WriterTo 会将所有数据写入 w 或者当写入发生错误时中断操作。返回值 n 代表写入的字节数。err 代表在写入过程中发生的错误。
如果Copy 函数的 src 实现了WriterTo方法,那么在 Copy 函数中将会使用 WriterTo 接口。