介绍
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包更合理)