io包提供了对I/O操作的基本接口。本包的基本任务是包装这些操作已有的实现,使之成为共享的公共接口,因为这些接口对底层实现包装,除非得到其它方面的通知,客户端不应假设它们是并发执行安全的。 这个包在日常的开发中可能用的不多,本章主要对包的接口做说明,可以做的代码示例不多,具体的代码实例就用文件的I/O来举例,网络IO不好模拟。不过都是IO,原理上来说都是一样的
这个包定义了很多的IO接口,每个接口都有特定的方法,但这些接口本包都不提供实现,因为这个包是提供对操作系统底层IO的封装,包里面的基本所有接口都有其它标准库实现,比如os包的File结构体就实现了本包的IO接口,还有 http包也实现了本包的IO接口;所以这个包大多数都是 抽象接口,具体的可用方法只有几个,我们先来看几个基础方法,再看包里面的接口。
不过在认识本包的几个方法之前,我们先看三个IO层最基础的接口,(go编程中,所有可以操作IO的结构体基本都实现了以下三个方法)对包有一个大概的了解:
// Reader接口,有一个Read方法,Writer接口有一个Write方法,Closer接口有一个Close,这是标准的读写关闭接口,实现了这些方法的结构体(例如os包的File结构体) type Reader interface { Read(p []byte) (n int, err error) } // Writer接口用于包装基本的写入方法。,os包File结构体也实现了这个接口 type Writer interface { Write(p []byte) (n int, err error) } // Closer接口是标准的关闭IO流的接口,基本所有实现了IO接口的结构体这个接口也是实现了的 type Closer interface { Close() error }
下面我们来看os包的几个可用方法:
func TeeReader(r Reader, w Writer) Reader => 这个方法接受一个可读流和一个可写流,返回一个可读的流,然后只要从返回的可读流中读取的数据,都会自动写入到传入可写流w里面,不好理解看下面的例子:
func main() {
wd,_ := os.Getwd() // 获取工作路径
fileRead,_ := os.Open(wd+"/src/read.txt") // 打开一个文件(这个文件事先创建好了,并写有一行hello world)
fileWrite,_ := os.Create(wd+"/src/write.txt") // 创建并打开一个可写的文件(这个文件不存在,我们通过代码把它创建出来)
read := io.TeeReader(fileRead,fileWrite) // 创建一个读取的reader
b := make([]byte,1024) // 创建一个byte切片保存数据
read.Read(b) // 从可读的流中读取内容
// 上面Read方法执行,实际是从fileRead中读取数据,然后又将数据写入到了fileWrite中,结果就是,write.txt文件中写入了read.txt中的数据
}
func MultiReader(readers ...Reader) Reader => 这个方法接受一个或多个可读流,将这些可读流合并起来,返回一个总的新的可读流,读取返回的可读流实际是依次读取传入的可读流,当传入的所有的可读流都没有可读数据时候,才返回EOF
func MultiWriter(writers ...Writer) Writer => 这个方法接受多个可写流,返回一个总的可写流,当想总的可写流中写入数据时,将向传入的所有可写流写入数据
func Copy(dst Writer, src Reader) (written int64, err error) => 将src中数据拷贝到dst中,返回拷贝的字节数
func main() {
wd,_ := os.Getwd() // 获取工作路径
fileRead,_ := os.Open(wd+"/src/read.txt") // 打开一个文件(文件里面有一行hello world)
fileWrite,_ := os.OpenFile(wd+"/src/write.txt",os.O_WRONLY, 777) // 打开一个可写的文件,第二个参数打开文件的模式,这里为只写;最后一个参数为文件的权限
io.Copy(fileWrite,fileRead) // 将read.txt的内容拷贝到write中
// f执行完成后,查看write.txt可以看到,成功将read.txt中的内容拷贝了过来
}
func CopyN(dst Writer, src Reader, n int64) (written int64, err error) => 将src中n个字节的数据拷贝到dst中,只有当err为nil时,返回的written才会等于n,跟Copy不同的是,后者可以指定拷贝数据的大小。不再演示
func ReadAtLeast(r Reader, buf []byte, min int) (n int, err error) => 从r至少读取min字节数据填充进buf。函数返回写入的字节数和错误(如果没有读取足够的字节)。 只有没有读取到字节时才可能返回EOF;如果读取了有但不够的字节时遇到了EOF,函数会返回ErrUnexpectedEOF。 如果min比buf的长度还大,函数会返回ErrShortBuffer。只有返回值err为nil时,返回值n才会不小于min。
func ReadFull(r Reader, buf []byte) (n int, err error) => 从r中读取len(buf)字节数据填充进buf。 函数返回写入的字节数和错误(如果没有读取足够的字节)。只有没有读取到字节时才可能返回EOF;如果读取了有但不够的字节时遇到了EOF,函数会返回ErrUnexpectedEOF。 只有返回值err为nil时,返回值n才会等于len(buf)。
func WriteString(w Writer, s string) (n int, err error) => 将字符串s的内容写入w中。如果w已经实现了WriteString方法,函数会直接调用该方法。
至此,io包的可用方法就算介绍完了,都是几个对读写的操作方法。开发中用的也不算不多,但也有用到的地方(个人认为)。
前面已经介绍了Reader,Writer,Closer接口。
type Seeker interface { Seek(offset int64, whence int) (int64, error) } // Seeker接口用于包装基本的移位方法。
type ReadCloser interface { Reader Closer } // ReadCloser接口聚合了基本的读取和关闭操作。
type WriteCloser interface { Writer Closer } // WriteCloser接口聚合了基本的写入和关闭操作。
type WriteSeeker interface { Writer Seeker } // WriteSeeker接口聚合了基本的写入和移位操作。
type ReadWriter interface { Reader Writer } // ReadWriter接口聚合了基本的读写操作。
type ReadWriteCloser interface { Reader Writer Closer } // ReadWriteCloser接口聚合了基本的读写和关闭操作。
type ReadWriteSeeker interface { Reader Writer Seeker } // ReadWriteSeeker接口聚合了基本的读写和移位操作。
type ReaderAt interface { ReadAt(p []byte, off int64) (n int, err error) } // ReaderAt接口包装了基本的ReadAt方法。
type WriterAt interface { WriteAt(p []byte, off int64) (n int, err error) } // WriterAt接口包装了基本的WriteAt方法。
以上已经包含了io包的80%的接口,全做了解,前面已经说明,这些接口都是在其它包提供实现的,io包只是提供定义,还有几个接口就不放上来了,因为也都是上面的接口各种变种,用到的时候再去查看吧,文章篇幅已经太长了,这些也全做了解,不过几个基本的接口还是要知道,比如Reader和Writer以及Closer接口,这三个接口是IO层最基础的接口
文档地址:https://studygolang.com/pkgdoc