Go语言基础(三)输入输出接口

本文主要介绍了Go语言输入输出接口。

关键词:golang

基本的IO接口

Reader接口

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

将len(p)个字节读入到p中,返回读取的字节数n以及任何的错误。即使Read返回的n<len(p),他也会在调用过程中占用len(p)个字节作为暂存空间。若可读取的数据不到len(p)个字节,会返回可用数据,而不是等待更多数据。

当Read在成功读取n个字节后,遇到一个错误或者EOF,会返回读取的字节数,可能会在本次的调用中返回一个non-nil错误,或者在下一次调用中返回这个错误(n为0)。一般情况下,Reader会返回非0字节数n,若n=len(p)个字节从输入源内的结尾处由Read返回,Read可能返回err==EOF或者err==nil,并且之后的Read()都应该返回(n:0, err:EOF).

调用者在考虑错误之前应当首先处理返回的数据。这样做可以正确的处理在读取一些字节后产生的I/O,允许EOF出现。

Reader的接口方法集只包含一个Read方法,实现了Read方法的类型都满足io.Reader接口,也就是说在需要io.Reader的地方,可以传递实现了Read()方法的实例。

举例说明Reader接口的方法:

1
2
3
4
5
6
7
8
func ReadFrom(reader io.Reader, num int)([]byte, error) {
p := make([]byte, num)
n, err := reader.Read(p)
if n > 0 {
return p[:n], nil
}
return p, err
}

ReadFrom函数将io.Reader作为参数,ReadForm可以从任意的地方读取数据,只要来源实现了io.Reader接口。可以从标准输入、文件、字符串读取数据:

1
2
3
4
5
6
// 标准输入
data, err = ReadFrom(os.Stdin, 11)
// 普通文件读取,其中file是os.File的实例
data, err = ReadFrom(file, 9)
// 从字符串读取
data, err = ReadFrom(strings.NewReader("form string"), 12)

Writer 接口

1
2
3
type Writer interface {
Wirte(p []byte) (n int, err error)
}

将len(p)个字节写入基本数据流中,返回从p中被写入的字节数n,以及任何遇到的引起的提前停止的错误。若Write返回的n<len(p),就必须返回一个非nil的错误。

所有实现了Write方法的类型都实现了io.Writer接口。

1
2
3
func Println(a ...interface{})(n int, err error) {
return Fprintln(os.Stdout, a...)
}

实现了Reader接口或者Writer接口的类型

  • os.File同时实现了io.Reader和io.Writer
  • strings.Reader实现了io.Reader
  • bufio.Reader/Writer 分别实现了 io.Reader 和 io.Writer
  • bytes.Buffer同时实现了io.Reader和io.Writer
  • bytes.Reader实现了io.Reader
  • compress/gzip.Reader/Writer 分别实现了io.Reader和io.Writer
  • crypto/cipher.StreamReader/StreamWriter 分别实现了 io.Reader 和 io.Writer
  • crypto/tls.Conn同时实现了io.Reader和io.Writer
  • encoding/csv.Reader/Writer 分别实现了 io.Reader 和 io.Writer
  • mine/multpart.Part实现了io.Reader
  • net/conn分别实现了io.Reader和io.Writer(Conn接口定义了Read/Write)

Closer接口

1
2
3
type Closer interface {
Close() error
}

该接口比较简单,只有一个close()方法,用于关闭数据流;

文件、归档、数据库链接、Socket等需要手动关闭的资源都实现了Closer接口;

实际编程中通常将Close方法的调用放在defer语句中。

ioutil 方便的IO操作函数集

NopCloser函数

有时候我们需要传递一个io.ReadCloser实例,而我们现在有一个io.Reader实例。

使用NopCloser包装一个Reader,返回一个io.ReaderCloser,相应的Close方法什么也不做,只是返回nil;

比如在标准库net/http包中的NewRequest,接收一个io.Reader的body,实际上Request的Body的类型是io.ReadCloser,因此代码内部做了判断:

如果传入的io.Reader也实现了io.ReaderCloser接口,则转换,否则通过ioutil.NopCloser包装一下。

ReadAll函数

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

一次性读取io.Reader中的所有数据

ReadDir函数

输出某目录下面的所有文件(包括子目录)

ReadFile和WriteFile函数

ReadFile读取整个文件的内容。

1
func ReadFile(filename string)([]byte, error)

从指定的filename的文件中读取数据并返回文件的内容,成功的调用返回的err为nil而非EOF。因为本函数定义为读取整个文件不会将读取的EOF视为报告的错误

WriteFile将data写入filename文件中,当文件不存在时会根据perm指定的权限创建一个,文件存在时会先清空内容,对于perm参数,可以指定为0666.

TempDir和TempFile函数

一般操作系统都会允许创建临时目录,比如linux下的/tmp目录。

通过TempDir可以创建一个临时目录,用于存放编译过程的临时目录

1
b.work, err = ioutil.TempDir("", "tmp")

如果第一个参数为空,表面在系统默认的临时目录中创建临时目录,第二个参数指定临时目录的前缀,函数返回临时目录的路径;

1
f1, err := ioutil.TempFile("", "gofmt")

创建者创建的临时变量和临时目录要负责删除这些临时目录和文件,比如删除临时文件:

1
2
3
4
defer func() {
f.close()
os.Remove(f.Name())
}