Golang标准库——io

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 }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值