// io包提供了原始I/O的基础接口 // 它的主要工作是去包含这些原始I/O已经存在的实现 // 比如在os包中的这些,抽象出功能做成共享接口,加上其它相关的原始I/O // 因为这些接口和原始I/O包裹着各种各样的实现的低级操作,除非非常了解客户端否则不能假定他们是并发安全的 package my_io import "errors" // Seek值的来源 const ( SeekStart = 0 //seek对应文件的起始处 SeekCurrent = 1 // seek对应当前的偏距 SeekEnd = 2 // seek对应结尾 ) // ErrShortWrite意味着一个write接收到少于要求字节数的数据,并没有返回一个明确的错误 var ErrShortWrite = errors.New("short write") // ErrShortBuffer意味着一个read需要一个比提供更长的buffer var ErrShortBuffer = errors.New("short buffer") // EOF是Read没有更多输入的时候返回的一个错误 // 函数只有要发送一个优雅结束输入的信号时返回一个EOF // 如果EOF在一个结构化数据流中意外发生,那么合适的错误是返回ErrUnexpectedEOF或给出更多详细信息的其它错误 var EOF = errors.New("EOF") // ErrUnexpectedEOF意味着在要读取一个固定大小的数据块或者数据结构的中途遇到了EOF var UnExpectedEOF = errors.New("unexpected EOF") // ErrNoProgress是io.Reader的一些客户端在多次调用Read却没有返回任何数据和错误时返回的,通常标志着io.Reader错误的实现。 var ErrNoProgress = errors.New("multiple Read calls return no data or error") // Reader是包含着基础Read方法的接口 // Read读取长度为len(p)的字节到p中。它返回读取到的字节数以及遇到的任何错误(0<=n<=len(p)) // 即使返回的字节数少于len(p),在调用过程中也会使用整个p作为暂存空间 // **** 如果可读取的字节数少于len(p),按照惯例会返回可读取到的字节而不是等待更多。这和ReadAt是不同的 // // 当在成功读取n>0个字节后遇到错误或者读到文件结尾的情况,返回读取到的字节数以及可能返回非空的错误。或者从下次调用中返回n=0个字节数以及非空的错误。 // 一个具体的案例是:一个Reader在输入流结束的时候返回非零的字节数的同时,可能返回err==EOF或者err==nil。下一次调用会返回0,EOF // // 调用者在考虑错误前应先处理读取到的字节。这样做能正确处理读取了一些字节和允许的EOF行为后发生的I/O错误。 // // 返回0字节并返回空的错误是不友好的,除非len(p)==0。调用者应该忽视这种情况当做什么都没发生。特别注意这并不意味着EOF。 // // 所有实现一定不能保留p type Reader interface { Read(p []byte) (n int, err error) } // Writer是包含基础Write的接口 // // Write把p中len(p)个字节写入到潜在的数据流中。它返回从p中写入的字节数(0<=n<=len(p))和造成写入动作提早结束的错误。 // Write在返回字节数n<len(p)的情况下必须返回一个非空的错误 // 我们一定不能修改切片数据,即使是短暂的也不可以。 // // 所有实现一定不能保留p type Writer interface { Write(p []byte) (n int, err error) } // Closer是包含着基本Close方法的接口 // // 在首次调用后的Close行为是未定义的。 // 具体的实现可以查阅它们自己行为的文档 type Closer interface { Close() error } // Seeker是包含着基本Seek方法的接口 // // Seek为下一次读取或写入设置偏距,具体解释看whence: // SeekStart表示文件的开始 // SeekCurrent表示当前的偏距 // SeekEnd表示结尾 // Seek返回相对于开始的新的偏距和一个错误(如果有的话) // 设置偏距到文件开始之前是错误的 // 设置任何位置的偏距是合法的,但是接下来的在潜在的对象上的I/O操作行为是依赖于实现的。 type Seeker interface { Seek(offset int64, whence int) (int64, error) } // ReadWriter是组合基础Read和Write方法的接口 type ReadWriter interface { Reader Writer } // ReadCloser是组合基础Read和Close方法的接口 type ReadCloser interface { Reader Closer } // WriterCloser是组合基础Write和Close方法的接口 type WriteCloser interface { Writer Closer } // ReadWriteCloser是组合基础Read,Write和Close方法的接口 type ReadWriteCloser interface { Reader Writer Closer } // ReadSeeker是组合基础Read和Seek方法的接口 type ReadSeeker interface { Reader Seeker } // ReadWriteSeeker是组合基础Read,Write和Seek方法的接口 type ReadWriteSeeker interface { Reader Writer Seeker } // ReaderFrom是包含着ReadFrom方法的接口 // // ReadFrom从r中读取数据直到遇到EOF或者错误 // n是从r中读取到的字节数 // 在读取过程中,任何错误都期望是io.EOF,并且它也会返回 // // Copy函数如果可以的话会使用ReaderFrom type ReaderFrom interface { ReadFrom(r Reader) (n int64, err error) } // WriterTo是包含着WriteTo方法的接口 // // WriteTo是把数据写入到w中直到没有数据可写或者发生错误。返回的数字是已经写入的字节数。在写入过程中遇到的任何错误也会被返回。 // Copy函数会优先使用WriterTo type WriterTo interface { WriteTo(w Writer) (n int64, err error) } // ReaderAt是包含着ReadAt方法的接口 // ReadAt在潜在的输入源从偏距off开始读取len(p)个字节到p中。返回读取到的字节数(0<=n<=len(p))和任何遇到的错误。 // // 当ReadAt返回的字节数n<len(p)时,也会返回一个错误来解释为什么没有更多的字节返回,从这方面来说,ReadAt是比Read要严格的 // // 即使ReadAt可读取到的字节少于len(p),在调用过程中也会使用整个p作为暂存空间 // ***如果有可以读取的字节但是数量少于len(p),ReadAt会阻塞,直到要么读取到所有数据,要么有错误发生。这点和Read是不同的。 // // 如果ReadAt在输入源结尾返回len(p)个字节,ReadAt应要么返回err==EOF或者err==nil // // 如果ReadAt正在用一个seek offset从输入源读取数据,ReadAt既不应该影响潜在的seek offset,也不应该被潜在的seek offset影响 // // ReadAt的客户端在相同的输入源可以并行地调用ReadAt // // 所有的实现不能保留p type ReaderAt interface { ReadAt(p []byte, off int64) (n int, err error) } // WriterAt是一个包含着基础WriteAt方法的接口 // // WriteAt从p将len(p)个字节在off位置写入到潜在的数据流中 // 它返回从p中写入的字节数和造成写入动作提前结束的错误 // WriteAt如果返回的字节数小于len(p),则必须返回一个非空的错误 // // 如果WriteAt正在用一个seek偏距写入到目标中,WriteAt既不应该影响潜在的seek偏距也不应该被其影响 // 如果范围没有重叠的话,在同一个目标上,WriteAt的客户端可以并发地调用WriteAt方法 // // 所有实现一定不能保留p type WriterAt interface { WriteAt(p []byte, off int64) (n int, err error) } // ByteReader是一个包含ReadByte方法的接口 // // ReadByte从输入中读取并返回下一个字节和遇到的错误 // 如果返回了一个错误,那么将不会从输入中消费一个字节,并且返回的字节值是未定义的 type ByteReader interface { ReadByte() (byte, error) } // ByteScanner是一个把UnreadByte方法和基础ReadByte方法加到一起的接口 // // UnreadByte使下一次对ReadByte的调用跟前一次调用一样返回相同的字节 // 如果中间没有调用ReadByte而连续调用两次UnreadByte的话可能会发生错误 type ByteScanner interface { ByteReader UnreadByte() error } // ByteWriter是一个包含着WriteByte方法的接口 type ByteWriter interface { WriteByte(c byte) error } // RuneReader是一个包含着ReadRune方法的接口 // // ReadRune读取单个UTF-8编码的Unicode字符并将这个rune返回并且返回它的字节大小 // 如果没有可得到的字符,将会设置错误 type RuneReader interface { ReadRune() (r rune, size int, err error) } // RuneScanner是一个将UnreadRune方法和基础的ReadRune方法加在一起的接口 // // UnreadRune造成下一次对ReadRune的调用和前一次对ReadRune的调用一样返回相同的rune // 连续两次调用UnreadRune而中间不调用ReadRune可能会报错 type RuneScanner interface { RuneReader UnreadRune() error } // StringWriter是一个包含WriteString方法的接口 type StringWriter interface { WriteString(s string) (n int, err error) } // WriteString将字符串s的内容写入到w(w接收字节切片) // 如果w实现了StringWriter接口,它的WriteString方法将被直接调用 // 否则w.Write被精确调用一次 func WriteString(w Writer, s string) (n int, err error) { if sw, ok := w.(StringWriter); ok { return sw.WriteString(s) } return w.Write([]byte(s)) } // ReadAtLeast从r中读取数据到buf直到至少已经读取了min个字节 // 它返回复制的字节数以及如果读取了少于min个字节时的错误 // 只有当没有字节可读取的时候error才为EOF // 如果min大于len(buf),ReadAtLeast返回ErrShortBuffer错误 // 对于返回结果,当且仅当err==nil时,n>=min // 如果r返回了一个错误但是已读取的字节大于min,那么这个错误将被丢弃 func ReadAtLeast(r Reader, buf []byte, min int) (n int, err error) { if len(buf) < min { return 0, ErrShortBuffer } for n < min && err == nil { var nn int nn, err = r.Read(buf[n:]) n += nn } if n >= min { err = nil } else if n > 0 && err == EOF { err = UnExpectedEOF } return } // ReadFull从r中读取精确len(buf)个字节到buf // 它返回复制的字节数和一个如果读取了少于len(buf)个字节的错误 // 只有当没有字节可读的时候错误才会为EOF // 如果只读取了部分字节而不是len(buf)个字节就发生了EOF,那么ReadFull会返回UnexpectedEOF错误 // 在返回上,当且仅当err==nil的时候,n==len(buf) // 如果在读取过程中已经读了至少len(buf)个字节然后遇到了错误,那么这个错误将被丢弃 func ReadFull(r Reader, buf []byte) (n int, err error) { return ReadAtLeast(r, buf, len(buf)) } // CopyN从src拷贝n个字节(或者遇到一个错误)到dst // 它返回拷贝的字节数和在拷贝过程中最先遇到的错误 // 在返回上,当且仅当err==nil的时候,written==n // // 如果dst实现了ReadFrom接口,copy会用它来实现 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提前停止,也必须是EOF err = EOF } return } // Copy从src中拷贝数据到dst,直到src遇到EOF或者拷贝期间发生一个错误 // 它返回已经拷贝的字节数和在拷贝时遇到的第一个错误(如果有的话) // // 一次成功的拷贝是返回err==nil而不是err==EOF // 因为Copy本来就是被定义成从src中读取直到EOF,它不会把EOF当做一个错误上报 // // 如果src实现了WriterTo接口,那么copy是靠调用WriteTo(dst)方法来实现 // 否则如果dst实现了ReaderFrom接口,那么copy是靠调用ReadFrom(src)方法来实现 func Copy(dst Writer, src Reader) (written int64, err error) { return copyBuffer(dst, src, nil) } // CopyBuffer和Copy是一样的除了它是通过提供的buf来组织(如果是必须的话)而不是自动分配一个临时的buf。 // 如果buf是nil的话,会自动分配一个 // 否则如果len(buf)为0的话,会panic func CopyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) { if buf != nil && len(buf) == 0 { panic("empty buffer in io.CopyBuffer") } return copyBuffer(dst, src, buf) } // copyBuffer是Copy和CopyBuffer的具体实现 // 如果buf为nil,那么自动分配一个 func copyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) { // 如果reader实现了WriteTo方法,用它来做copy,避免一次分配和拷贝 if wt, ok := src.(WriterTo); ok { return wt.WriteTo(dst) } // 相似的,如果Writer实现ReadFrom方法,那么就用它来实现copy if rf, ok := dst.(ReaderFrom); ok { rf.ReadFrom(src) } // 如果没有buf,则创建一个 if buf == nil { // 默认是3kb size := 32 * 1024 // 如果src是*LimitedReader类型并且size比l.N大,则根据l.N的情况调整size if l, ok := src.(*LimitedReader); ok && int64(size) > l.N { if l.N < 1 { size = 1 } else { size = int(l.N) } } // 根据最终size创建buf buf = make([]byte, size) } // 循环读取写入作为复制的实现 for { // 先从Reader中读取 nr, er := src.Read(buf) // 在错误处理之前先处理已经读取到的字节 if nr > 0 { // 把已经读到的字节写入 nw, ew := dst.Write(buf[:nr]) // 如果写入了数据则更新written if nw > 0 { written += int64(nw) } // 如果写入发生错误,则中断复制,并将错误置为ew if ew != nil { err = ew break } // 如果写入的字节数少于读取的字节数,则将错误置为ErrShortWrite错误并中断复制 if nw < nr { err = ErrShortWrite break } } // 如果读取有错误 if er != nil { // 并且er!=EOF,则返回错误 if er != EOF { err = er } break } } return } // LimitReader返回一个从r中读取,但是在读取n个字节后停止并返回EOF // 潜在的实现是一个*LimitedReader func LimitReader(r Reader, n int64) Reader { return &LimitedReader{ R: r, N: n, } } // 一个LimitedReader从R中读取但是限制数据量只到N字节 // 每次对Read的调用要更新N以反映最新剩余可以读取的字节数 // 当N<=0或者潜在的R返回EOF时,Read会返回EOF type LimitedReader struct { R Reader // 潜在的Reader N int64 // 保存的最大字节数 } 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 } func NewSectionReader(r ReaderAt, off int64, n int64) *SectionReader { return &SectionReader{ r: r, base: off, off: off, limit: off + n, } } // SectionReader在一个潜在的ReaderAt的片段上上实现了Read Seek 和ReadAt type SectionReader struct { r ReaderAt base int64 off int64 limit int64 } func (s *SectionReader) Read(p []byte) (n int, err error) { // 如果偏距大于限制读取的位置,则直接返回EOF if s.off >= s.limit { return 0, EOF } if max := s.limit - s.off; int64(len(p)) > max { p = p[:max] } n, err = s.r.ReadAt(p, s.off) s.off += int64(n) return } var errWhence = errors.New("Seek: invalid whence") var errOffset = errors.New("Seek: invalid offset") 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[:max] n, err = s.r.ReadAt(p, off) if err == nil { err = EOF } return n, err } return s.r.ReadAt(p, off) } // Size返回这个片段的字节大小 func (s *SectionReader) Size() int64 { return s.limit - s.base } // TeeReader返回一个Reader--这个Reader把从r中读取到的数据直接写入到w // 通过它从r中的所有读取相应地写入到w。 // 没有内部缓冲区,写操作必须在读完成之前完成 // 任何写操作进行时的错误都会作为读操作错误返回 func TeeReader(r Reader, w Writer) Reader { return &teeReader{ r: r, w: w, } } type teeReader struct { r Reader w Writer } func (t *teeReader) Read(p []byte) (n int, err error) { n, err = t.r.Read(p) if n > 0 { if n, err := t.w.Write(p[:n]); err != nil { return n, err } } return }
有疑问加站长微信联系(非本文作者)