虽然 io 包提供了不少类型、方法和函数,但有时候使用起来不是那么方便。比如读取一个文件中的所有内容。为此,标准库中提供了一些常用、方便的IO操作函数。

说明:这些函数使用都相对简单,一般就不举例子了。

1.1. 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的实现。

1.2. ReadAll 函数

很多时候,我们需要一次性读取io.Reader中的数据,通过上一节的讲解,我们知道有很多种实现方式。考虑到读取所有数据的需求比较多,Go提供了ReadAll这个函数,用来从io.Reader中一次读取所有数据。

func ReadAll(r io.Reader) ([]byte, error)

阅读该函数的源码发现,它是通过bytes.Buffer中的ReadFrom来实现读取所有数据的。

1.3. ReadDir 函数

笔试题:编写程序输出某目录下的所有文件(包括子目录)

是否见过这样的笔试题?

在Go中如何输出目录下的所有文件呢?首先,我们会想到查os包,看File类型是否提供了相关方法(关于os包,后面会讲解)。

其实在ioutil中提供了一个方便的函数:ReadDir,它读取目录并返回排好序的文件和子目录名([]os.FileInfo)。通过这个方法,我们可以很容易的实现“面试题”。

下面的例子实现了类似Unix中的tree命令,不过它在windows下也运行的很好哦。

// 未实现-L参数功能
func main() {if len(os.Args) > 1 {Tree(os.Args[1], 1, map[int]bool{1:true})}
}// 列出dirname目录中的目录树,实现类似Unix中的tree命令
// curHier 当前层级(dirname为第一层)
// hierMap 当前层级的上几层是否需要'|'的映射
func Tree(dirname string, curHier int, hierMap map[int]bool) error {dirAbs, err := filepath.Abs(dirname)if err != nil {return err}fileInfos, err := ioutil.ReadDir(dirAbs)if err != nil {return err}fileNum := len(fileInfos)for i, fileInfo := range fileInfos {for j := 1; j < curHier; j++ {if hierMap[j] {fmt.Print("|")} else {fmt.Print(" ")}fmt.Print(strings.Repeat(" ", 3))}// map是引用类型,所以新建一个maptmpMap := map[int]bool{}for k, v := range hierMap {tmpMap[k] = v}if i+1 == fileNum {fmt.Print("`")delete(tmpMap, curHier)} else {fmt.Print("|")tmpMap[curHier] = true}fmt.Print("-- ")fmt.Println(fileInfo.Name())if fileInfo.IsDir() {Tree(filepath.Join(dirAbs, fileInfo.Name()), curHier+1, tmpMap)}}return nil
}

1.4. ReadFile 和 WriteFile 函数

ReadFile 读取整个文件的内容,在上一节我们自己实现了一个函数读取文件整个内容,由于这种需求很常见,因此Go提供了ReadFile函数,方便使用。ReadFile的是实现和ReadAll类似,不过,ReadFile会先判断文件的大小,给bytes.Buffer一个预定义容量,避免额外分配内存。

WriteFile 函数的签名如下:

func WriteFile(filename string, data []byte, perm os.FileMode) error

它将data写入filename文件中,当文件不存在时会创建一个(文件权限由perm指定);否则会先清空文件内容。对于perm参数,我们一般可以指定为:0666,具体含义os包中讲解。

小提示

ReadFile 源码中先获取了文件的大小,当大小 < 1e9时,才会用到文件的大小。按源码中注释的说法是FileInfo不会很精确地得到文件大小。

1.5. 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())
}()

1.6. 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字节,其他的会丢弃(当然,这个也不会读取)。

go 输入输出流(ioutil)相关推荐

  1. python输入输出流详解_输入输出流的概念

    Java中的文件复制相较Python而言,涉及到输入输出流的概念,实现中会调用很多对象,复杂很多,在此以文件复制进行简单总结. 这里是一个简单的处理代码: import java.io.*; publ ...

  2. C++ 输入输出流 文本文件 二进制文件读写

    文本文件/ASCII文件(能直接显示内容,费存储空间):文件中每一个字节中均以ASCII代码形式存放数据,即一个字节存放一个字符,这个文件就是ASCII文件或称字符文件. 二进制文件(不能显示内容,节 ...

  3. c++一日一练:让标准的输入输出流关联一个缓冲区

    上篇文章讲述了如何创建自己的标准输入输出,但是如何将标准的输入输出流进行重定向呢: 下面是一个具体的方法: fp = _fdopen( hConHandle, "w" );    ...

  4. Java IO (二),常见的输入/输出流

    字节流和字符流 InputStream和Reader InputStream和Reader两个抽象类是所有输入流的基类,本身并不能创建实例来执行输入,但它们将成为所有输入流的模板.他们的方法是所有输入 ...

  5. java输出流输入流的使用_Java中的IO流之文件输入输出流

    Java中的IO流之文件输入输出流 1.文件流介绍 文件流是以字节为单位进行读写文件的,所以属于字节流,并且是低级流.文件流位于java.io包下. 输入输出流分别是FileInputSteam和Fi ...

  6. java输出流缓冲区内容清除,Java输入输出流与缓冲区的使用

    Java输入输出流与缓冲区的使用,有需要的朋友可以参考下. 一,Input/Output流: 将外设中的数据读取到内存中就是输入. 将内存中的数据写入到外设中就是出. I/O流就是用来处理设备间的 . ...

  7. java实验 输入输出流_java实验七 输入输出流

    有关java的实验和程序 实验七 输入输出流 一.实验目的和要求 目的: 1.掌握使用输入输出流进行文件的读写操作. 要求: 1.实验报告给出内容1,2的填充代码以及内容3的全部源代码. 二.实验内容 ...

  8. java实验七输入输出流_实验六_Java的输入输出流

    JAVA的输入输出流 实验六 Java的输入输出流 实验目的 1. 理解I/O流的概念,掌握其分类 2. 掌握文本文件读写.二进制文件读写 实验环境 JDK1.4以上版本, Eclipse集成开发环境 ...

  9. 【java开发系列】—— java输入输出流

    前言 任何语言输入输出流都是很重要的部分,比如从一个文件读入内容,进行分析,或者输出到另一个文件等等,都需要文件流的操作.这里简单介绍下reader,wirter,inputstream,output ...

最新文章

  1. 微软:杀死那个曾经全球第一的浏览器
  2. 建筑物占据的网格数目的确定(三)
  3. 为什么C语言是非形式化的,《数据结构C语言版》——绪论
  4. RTEMS文件系统(4):系统调用开发信息(上)
  5. shell字符串截取总结
  6. hdu 1042 N!(大数)
  7. Akamai托管服务应对多重网络性能挑战
  8. module_param的使用
  9. python 开闭原则_Python 装饰器@,对函数进行功能扩展操作示例【开闭原则】
  10. sql server 2008安装图解
  11. JavaScript DOM操作总结
  12. oracle的热备份和冷备份
  13. linux挂载硬盘_玩客云刷机系统之挂载U盘/硬盘增加储存空间
  14. 云计算 码率适配限速_5G 成熟后,带宽足够且云计算力够大,会不会对 PC 的升级需求放缓?...
  15. 云计算时代IT产业六大发展趋势
  16. 分子量(Molar Mass, ACM/ICPC Seoul 2007, UVa1586)
  17. gds文件 导出_GaussDB 200使用GDS服务导入导出数据
  18. 天下难事必做于易 项目管理从简单做起(转)
  19. php利用表格敬将所选择的数据显示出来,单元格下拉筛选设置/Excel对筛选后的单元格进行下拉填充...
  20. 如何防止工具(八门神器)进行内存修改(转)

热门文章

  1. python自动化常见面试题_Python基础面试题80问 Python自动化开发
  2. greendao3.0版本更新 新增字段遇到的问题
  3. ARCGIS知乎上的好文章
  4. 【Tomcat】Tomcat Connector的三种运行模式【bio、nio、apr】
  5. C语言系列之自增自减运算符的用法(二)
  6. javascript深入浅出——学习笔记(六种数据类型和隐式转换)
  7. Android中各个权限详解
  8. iOS一段文字设置多种颜色格式
  9. 算法题003 斐波那契(Fibonacci)数列
  10. 字节跳动2019春招笔试——找零(JavaScript)