2 ioutil — 方便的IO操作函数集

2.1. NopCloser 函数

有时候我们需要传递一个 io.ReadCloser 的实例,而我们现在有一个 io.Reader 的实例,比如:strings.Reader ,这个时候 NopCloser 就派上用场了。它包装一个io.Reader,返回一个 io.ReadCloser ,而相应的 Close 方法啥也不做,只是返回 nil。

2.2. ReadAll 函数

很多时候,我们需要一次性读取 io.Reader 中的数据,通过上一节的讲解,我们知道有很多种实现方式。考虑到读取所有数据的需求比较多,Go 提供了 ReadAll 这个函数,用来从io.Reader 中一次读取所有数据。
    func ReadAll(r io.Reader) ([]byte, error)
阅读该函数的源码发现,它是通过 bytes.Buffer 中的 ReadFrom 来实现读取所有数据的。该函数成功调用后会返回 err == nil 而不是 err == EOF。

2.3. ReadDir 函数

读取目录并返回排好序的文件和子目录名( []os.FileInfo )。

2.4. ReadFile 和 WriteFile 函数

ReadFile 读取整个文件的内容,ReadFile 的实现和ReadAll 类似,不过,ReadFile 会先判断文件的大小,给 bytes.Buffer 一个预定义容量,避免额外分配内存。
ReadFile 函数的签名如下:
    func ReadFile(filename string) ([]byte, error)
函数文档:
ReadFile 从 filename 指定的文件中读取数据并返回文件的内容。成功的调用返回的err 为 nil 而非 EOF。因为本函数定义为读取整个文件,它不会将读取返回的 EOF 视为应报告的错误。(同 ReadAll )
WriteFile 函数的签名如下:
    func WriteFile(filename string, data []byte, perm os.FileMode) error
函数文档:
WriteFile 将data写入filename文件中,当文件不存在时会根据perm指定的权限进行创建一个,文件存在时会先清空文件内容。对于 perm 参数,我们一般可以指定为:0666,具体含义 os 包中讲解。
ReadFile 源码中先获取了文件的大小,当大小 < 1e9 时,才会用到文件的大小。按源码中注释的说法是 FileInfo 不会很精确地得到文件大小。

2.5. TempDir 和 TempFile 函数

    b.work, err = ioutil.TempDir("", "go-build")
第一个参数如果为空,表明在系统默认的临时目录( os.TempDir )中创建临时目录;第二个参数指定临时目录名的前缀,该函数返回临时目录的路径。
相应的,TempFile 用于创建临时文件。如 gofmt 命令的源码中创建临时文件:
    f1, err := ioutil.TempFile("", "gofmt")
参数和 ioutil.TempDir 参数含义类似。
需要注意:创建者创建的临时文件和临时目录要负责删除这些临时目录和文件。如删除临时文件:
    defer func() {
        f.Close()
        os.Remove(f.Name())
    }()

2.6. Discard 变量

ioutil.Discard是一个io.Writer变量,对它的所有写调用都成功,不做任何操作。
Discard is an io.Writer on which all Write calls succeed without doing anything.
As of Go 1.16, this value is simply io.Discard.
var Discard io.Writer = io.Discard