Go 语言 IO 函数集


ioutil 的IO函数集 io包提供 类型 方法和函数   标准库 提供了 常用方便的IO操作函数

NopCloser 函数

要传递一个 io.ReadCloser 实例 而现在有一个 io.Reader 实例
比如 strings.Reader 这个时候 NopCloser 就派上用场了 它包装一个io.Reader 返回一个io.ReadCloser 而相应的Close方法啥也不做 只是返回nil
比如 标准库net/http包中的 NewRequest 接收一个 io.Reader 的 body 而实际上 Request的Body的类型是 io.ReadCloser 因此 代码内部进行了判断 如果传递的io.Reader也实现了io.ReadCloser接口 则转换 否则通过ioutil.NopCloser包装转换一下
rc, ok := body.(io.ReadCloser)
if !ok && body != nil {
    rc = ioutil.NopCloser(body)
} 如果没有这个函数  看 NopCloser 的实现

ReadAll 函数

一次性读取 io.Reader 中的数据 很多种实现方式 考虑到读取所有数据的需求比较多 Go提供 ReadAll 函数 用来从 io.Reader 中一次读取所有数据
func ReadAll(r io.Reader) ([]byte, error)
是通过 bytes.Buffer中 ReadFrom 来实现读取所有数据的 该函数成功调用后 会返回 err == nil 而不是 err == EOF

ReadDir 函数

输出某目录下的所有文件/包括子目录
ioutil 提供了方便的函数 ReadDir  读取目录并返回排好序的文件和子目录名([]os.FileInfo) 很容易的实现“面试题”
func main() {
    dir := os.Args[1]
    listAll(dir,0)
}
func listAll(path string, curHier int){
    fileInfos, err := ioutil.ReadDir(path)
    if err != nil{fmt.Println(err); return}
    for _, info := range fileInfos{
        if info.IsDir(){
            for tmpHier := curHier; tmpHier > 0; tmpHier--{
                fmt.Printf("|\t")
            }
            fmt.Println(info.Name(),"\\")
            listAll(path + "\\" + info.Name(),curHier + 1)
        }else{
            for tmpHier := curHier; tmpHier > 0; tmpHier--{
                fmt.Printf("|\\t")
            }
            fmt.Println(info.Name())
        }
    }
}

ReadFile 和 WriteFile 函数

ReadFile 读取整个文件的内容  ReadFile的实现和ReadAll类似 不过 ReadFile 先判断文件的大小 给bytes.Buffer一个预定义容量 避免额外分配内存
func ReadFile(filename string) ([]byte, error)
从 filename 文件中读取数据 返回文件的内容 成功的调用 返回的err为nil 而非EOF
因为本函数定义为读取整个文件 不会将读取返回的EOF视为应报告的错误

WriteFile 函数

func WriteFile(filename string, data []byte, perm os.FileMode) error
将data写入filename 文件  文件不存在时 根据perm指定的权限创建  文件存在时先清空文件内容 对于perm参数 可指定为 0666 具体含义os包中讲解
ReadFile 先获取了文件的大小 当大小 < 1e9时 才会用到文件的大小 按源码中注释的说法是FileInfo不会很精确地得到文件大小

TempDir 和 TempFile 函数

操作系统 提供临时目录 如linux下 /tmp目录(通过os.TempDir()可 获取到) 自己需要创建临时目录 如Go工具链 源码中(src/cmd/go/build.go) 通过TempDir创建一个临时目录 用于存放编译过程的临时文件
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())
}()

Discard 变量

Discard 对应的类型(type devNull int)实现了io.Writer接口 为了优化io.Copy到Discard 避免不必要的工作 实现了io.ReaderFrom接口
devNull 在实现io.Writer接口时 只是简单的返回(标准库文件 src/pkg/io/ioutil.go)
func (devNull) Write(p []byte) (int, error) {
    return len(p), nil
}
而ReadFrom的实现是读取内容到一个buf中 最大也就8192字节 其他的会丢弃(当然 这个也不会读取)