io包提供了对I/O原语的基本接口。本包的基本任务是包装这些原语已有的实现(如os包里的原语),使之成为共享的公共接口,这些公共接口抽象出了泛用的函数并附加了一些相关的原语的操作。
io包中的源码都是BSD风格的。
1、io包中定义的error
// ErrShortWrite 当读取的字节不能满足需要的字节数时,就会返回该错误
var ErrShortWrite = errors.New("short write")
// errInvalidWrite 意味着返回一个不可能的字节数
var errInvalidWrite = errors.New("invalid write result")
// ErrShortBuffer 提供的缓冲区太小
var ErrShortBuffer = errors.New("short buffer")
// EOF当无法得到更多输入时,Read方法返回EOF。当函数一切正常的到达输入的结束时,就应返回EOF。
// 如果在一个结构化数据流中EOF在不期望的位置出现了,则应返回错误ErrUnexpectedEOF或者其它给出更多细节的错误。
var EOF = errors.New("EOF")
// ErrUnexpectedEOF 意味着EOF出现在了一个固定大小的块或者数据结构的中间位置
// 也就是文件没有读到结尾就出现了EOF
var ErrUnexpectedEOF = errors.New("unexpected EOF")
// 某些使用io.Reader接口的客户端如果多次调用Read都不返回数据也不返回错误时,就会返回本错误,
// 一般来说是io.Reader的实现有问题的标志。
var ErrNoProgress = errors.New("multiple Read calls return no data or error")
2、io包中的接口
2.1 Reader
Reader是一个包装了基本读方法的接口。
Read方法读取len§字节的数据到p中,它返回读取到的字节数和任何发生的错误。即使Read方法返回值n < len§,本方法在被调用时仍可能使用p的全部长度作为暂存空间。如果有部分可用数据,但不够len§字节,Read按惯例会返回可以读取到的数据,而不是等待更多数据。
Read 参数和返回值:
- p:缓冲区
- n:读取的字节数 0 <= n <= len§
- err:错误
type Reader interface {
Read(p []byte) (n int, err error)
}
2.2 Writer
Writer是一个包装了基本写方法的接口。
Write将len§个字节从p中写入底层数据流,返回写入的字节数和发生的任何导致写入提前停止的错误。如果写入的字节数小于len§它一定会返回一个非nil的错误。Writer一定不会修改传入的切片的数据。
type Writer interface {
Write(p []byte) (n int, err error)
}
2.3 Closer
Closer是一个包装了基本关闭方法的接口。例如:关闭文件。关闭socket
type Closer interface {
Close() error
}
2.4 Seeker
Seeker是一个包装了基本移位方法的接口。
Seek方法设定下一次读写的位置:偏移量为offset。Seek返回相对于文件的开始的新的偏移量和任何发生的错误。
type Seeker interface {
Seek(offset int64, whence int) (int64, error)
}
const (
SeekStart = 0 // 相对于文件开始位置
SeekCurrent = 1 // 相对于指针当前位置
SeekEnd = 2 // 相当于文件结尾的位置
)
2.5 ReaderFrom
ReadFrom从一个Reader中读取数据直到读完或者发生错误,返回值n为读取到的字节数。
type ReaderFrom interface {
ReadFrom(r Reader) (n int64, err error)
}
2.6 WriterTo
WriteTo向一个Writer中写入数据,直到数据全部写完或者发生错误。
type WriterTo interface {
WriteTo(w Writer) (n int64, err error)
}
2.7 ReaderAt
ReaderAt与Reader差不多,它可以指定读取的位置的偏移量。
type ReaderAt interface {
ReadAt(p []byte, off int64) (n int, err error)
}
2.8 WriterAt
WriterAt与Writer也差不多,它可以指定写入的位置的偏移量
type WriterAt interface {
WriteAt(p []byte, off int64) (n int, err error)
}
3、io包中的函数
3.1 ReadAtLeast
ReadAtLeast函数从Reader中读取至少min字节的数据,返回读取的字节数和发生的错误。如果在读取不到min字节的数据时遇到了EOF,它会返回ErrUnexpectedEOF。如果给的缓冲区的大小小于min,返回ErrShortBuffer。
func ReadAtLeast(r Reader, buf []byte, min int) (n int, err error) {
if len(buf) < min {
return 0, ErrShortBuffer
}
for n < min && err == nil { // 循环读取至少min字节的数据
var nn int
nn, err = r.Read(buf[n:])
n += nn
}
if n >= min {
err = nil
} else if n > 0 && err == EOF {
err = ErrUnexpectedEOF
}
return
}
3.2 ReadFull
ReadFull函数将读取至少len(buf)字节的数据,除非发生错误,它调用了ReadAtLeast函数。
func ReadFull(r Reader, buf []byte) (n int, err error) {
return ReadAtLeast(r, buf, len(buf))
}
3.3 CopyN
CopyN从一个Reader中拷贝N字节的数据到Writer中。
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
}
3.4 Copy
Copy函数从Reader中拷贝数据到Writer中,直到遇到EOF,返回copy的字节数以及发生的错误。
func Copy(dst Writer, src Reader) (written int64, err error) {
return copyBuffer(dst, src, nil)
}
3.5 CopyBuffer
CopyBuffer与Copy差不多。可以由用户自己提供缓冲区。
func CopyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) {
if buf != nil && len(buf) == 0 {
panic("empty buffer in CopyBuffer")
}
return copyBuffer(dst, src, buf)
}
func copyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) {
// 如果reader实现了WriterTo方法,直接使用该方法拷贝
if wt, ok := src.(WriterTo); ok {
return wt.WriteTo(dst)
}
// 同样的,如果writer实现了ReadFrom方法,直接使用该方法拷贝
if rt, ok := dst.(ReaderFrom); ok {
return rt.ReadFrom(src)
}
// 如果buf为nil,为其分配空间,最大为32k
if buf == nil {
size := 32 * 1024
if l, ok := src.(*LimitedReader); ok && int64(size) > l.N {
if l.N < 1 {
size = 1
} else {
size = int(l.N)
}
}
buf = make([]byte, size)
}
// 从Reader中拷贝数据到Writer
for {
nr, er := src.Read(buf)
if nr > 0 {
nw, ew := dst.Write(buf[0:nr])
if nw < 0 || nr < nw {
nw = 0
if ew == nil {
ew = errInvalidWrite
}
}
written += int64(nw)
if ew != nil {
err = ew
break
}
if nr != nw {
err = ErrShortWrite
break
}
}
if er != nil {
if er != EOF {
err = er
}
break
}
}
return written, err
}
3.6 ReadAll
ReadAll从一个Reader中读取数据直到全部读完或者发生错误。返回读取的数据的字节切片。
func ReadAll(r Reader) ([]byte, error) {
b := make([]byte, 0, 512)
for {
if len(b) == cap(b) {
// Add more capacity (let append pick how much).
b = append(b, 0)[:len(b)]
}
n, err := r.Read(b[len(b):cap(b)])
b = b[:len(b)+n]
if err != nil {
if err == EOF {
err = nil
}
return b, err
}
}
}
4、io包中的结构体及其方法
4.1 LimitedReader
LimitedReader从一个Reader中读取数据但限制了读取的字节数。
type LimitedReader struct {
R Reader // underlying reader
N int64 // max bytes remaining
}
func LimitReader(r Reader, n int64) Reader { return &LimitedReader{r, n} }
LimitedReader.Read
LimitedReader的Read方法从Reader中读取最多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)
return
}
4.2 SectionReader
SectionReader实现了Read、Seek和ReadAt等接口。
type SectionReader struct {
r ReaderAt
base int64
off int64
limit int64
}
func (s *SectionReader) Read(p []byte) (n int, err error) {
if s.off >= s.limit {
return 0, EOF
}
if max := s.limit - s.off; int64(len(p)) > max {
p = p[0:max]
}
n, err = s.r.ReadAt(p, s.off)
s.off += int64(n)
return
}
func (s *SectionReader) Seek(offset int64, whence int) (int64, error) {
switch whence {
default:
return 0, errWhence
case SeekStart:
offset += s.base
case SeekCurrent:
offset += s.off
case SeekEnd:
offset += s.limit
}
if offset < s.base {
return 0, errOffset
}
s.off = offset
return offset - s.base, nil
}
func (s *SectionReader) ReadAt(p []byte, off int64) (n int, err error) {
if off < 0 || off >= s.limit-s.base {
return 0, EOF
}
off += s.base
if max := s.limit - off; int64(len(p)) > max {
p = p[0:max]
n, err = s.r.ReadAt(p, off)
if err == nil {
err = EOF
}
return n, err
}
return s.r.ReadAt(p, off)
}
func (s *SectionReader) Size() int64 { return s.limit - s.base }