Go语言入门【四】:源码学习-io

介绍

package io主要包含以下文件:

  • io.go 基础的io操作,如读写,较底层
  • multi.go 多个Reader封装成一个
  • pipe.go
  • ioutil 常用操作
    • ioutil.go 封装了ioutil
    • tempfile.go 有关创建临时文件

Reader & Writer

这两个接口是用途最广的接口之一,所以重点学习一下,后续会用在os,net等各种常用包。

io.Reader

type Reader interface {
    Read(p []byte) (n int, err error)
}

io.Writer

type Writer interface {
    Write(p []byte) (n int, err error)
}

具体例子,以strings.Reader为例,代码:

package strings
...

type Reader struct {
    s        string
    i        int64 // current reading index
    prevRune int   // index of previous rune; or < 0
}

func (r *Reader) Read(b []byte) (n int, err error) {
    if r.i >= int64(len(r.s)) {
        return 0, io.EOF
    }
    r.prevRune = -1
    n = copy(b, r.s[r.i:])
    r.i += int64(n)
    return
}

可见该类满足io.Reader契约,所以使用时可以这样(清晰起见,以显式类型编码):

var strReader io.Reader = strings.NewReader("hello")
if _, err := io.Copy(os.Stdout, r); err != nil {
    log.Fatal(err)
}

从源码来看,
第一,实际上Reader就是封装了序列化数据的一个容器。这一点从命名上来讲可能不是那么明显,从名字上看,可能Reader只是一个调用者,需要从别的地方去『读取』数据,实际上大部分Reader本身包括了数据。
第二,Reader类似我们现在的优酷土豆播放器,能够记住上一次播放的位置,每次去观看都从上次看的接着看。

Copy

这个方法从前面也能看到十分常用
func Copy(dst Writer, src Reader) (written int64, err error)
作用是将src的内容写入到dst之中,

注意,在buildin中有一个copy方法与之类似,
func copy(dst, src []Type) int
只不过是处理[]byte类型。

查看io.Copy方法的源码,我们发现其中调用了
func copyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error)
并默认创建了一个buf,代码如下

if buf == nil {
    buf = make([]byte, 32*1024)
}

然后,内部调用了src.Read(buf),并在返回不为EOF的情况下将buf内容逐渐写入dst。加上一些错误处理。

Copy方法还有一个兄弟:io.CopyN:
func CopyN(dst Writer, src Reader, n int64) (written int64, err error)
最多拷贝n个字节。
与CopyN相反,还有一个方法:
func ReadAtLeast(r Reader, buf []byte, min int) (n int, err error)
该方法至少读取min个字节直到全部读完,否则将抛异常。
这个方法主要用途是保证byte的内容被完整的读取,见ReadFull:

func ReadFull(r Reader, buf []byte) (n int, err error) {
    return ReadAtLeast(r, buf, len(buf))
}

io/ioutil

相比之下io中的偏底层实现,ioutil的方法更加实用,常用方法有:

func ReadAll(r io.Reader) ([]byte, error)
将reader中的所有内容读取出来,返回字节数组,不需要自己提供字节数组

func ReadFile(filename string) ([]byte, error)
将一个文件名传入,返回内容字节数组

func WriteFile(filename string, data []byte, perm os.FileMode)error
将data写入文件,如果文件不存在,则以perm的模式创建文件

func ReadDir(dirname string) ([]os.FileInfo, error)
返回目录下的所有文件信息(个人认为这个方法出现得有点奇怪,应该在os包更合理)

    原文作者:纳达丶无忌
    原文地址: https://www.jianshu.com/p/1a616170ca16
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞