在上一篇里我们详细的看了io 包中各种io的操作方法,是不是有点蒙,简直就是个人骚操作。这里整理一下从 src 拷贝到dst的N中方法。
这里假设 dst 实现了Write 方法,src 实现了 Read 方法
io.Copy系
io.Copy(dst Writer, src Reader)
从 src 中拷贝数据到 dst,直到遇到 EOF或者错误为止。 需要注意的一点是读到EOF不会返回错误。
他底层其实是调用下面的 io.copyBuffer, 不过每次从 src-->dst 搬运的buffer是系统自动分配的32×1024 bytes。
src1 := bytes.NewBufferString("this is a test for io.Copy")
dst1 := bytes.NewBuffer([]byte{})
io.Copy(dst1, src1)
fmt.Println("dst after io.Copy = ", dst1.String(
io.CopyBuffer(dst Writer, src Reader, buf []byte)
原理和上面函数一样,不同点在于中间转运 buffer 可以自己指定。
注意这里的 buf 大小不能为0
src2 := bytes.NewBufferString("this is a test for io.CopyBuffer")
dst2 := bytes.NewBuffer([]byte{})
buf := make([]byte, 1024)
io.CopyBuffer(dst2, src2, buf)
fmt.Println("dst after copyBuffer = ", dst2.Strin
io.CopyN(dst Writer, src Reader, n int64)
从 src 中拷贝 n bytes的和数据到 dst。这里很巧妙的使用了LimitReader
src3 := bytes.NewBufferString("this is a test for io.CopyN")
dst3 := bytes.NewBuffer([]byte{})
io.CopyN(dst3, src3, 5)
fmt.Println("dst after copyN = ", dst3.Stri
上面几个函数的共同点在于他们底层都是调用:
io.copyBuffer(dst Writer, src Reader, buf []byte)
如果 src 实现了WriteTo 方法或者 dst 实现了 ReadFrom 就直接使用 src.WriteTo(dst) 或者 dst.ReadFrom(src)
Read 系
这里系列的方法前提是你src 必须实现了 Read 方法
直接调用 src 的Read 方法
src2 := bytes.NewBufferString("this is a test for directly Read")
dst2 := make([]byte, 10)
src2.Read(dst2)
fmt.Println("dst after copyBuffer = ", string(dst2))
io.ReadFull(r Reader, buf []byte
从 r 中读取 len(buf) 大小的数据到 buf,这里需要注意一下buf 和正式读到的数据大小之间的关系
读到的数据小于len(buf) 返回读到的数据 + 错误
err == nil 当且仅当 len(buf) == read size
数据没有读完但是遇到一个EOF 返回 ErrUnexpectedEOF
src3 := bytes.NewBufferString("this is a test")
dst3 := make([]byte, 15)
n, err = io.ReadFull(src3, dst3)
fmt.Println("dst after readFull = ", string(dst3), "n = ", n, "err = ", err)
io.ReadAtLeast(r Reader, buf []byte, min int)
从 r 中至少读取min bytes的数据到buf,错与信息基本和上面一样
如果min > len(buf) 返回 short buffer‘
err == nil 当且仅当 read size >= min
SectionReader/LimitReader etc
和普通的读没啥区别,不过这里通过选择和limit来保护的内存(防止恶意的请求把内存打爆)
ioutil系
ReadAll(r io.Reader) ([]byte, error)
这里系就这个一个方法,主要用来从http或者文件中读取数据(注意文件不要太大)。从r 中读取直到EOF,所以EOF并不会当成错误来返回。
三个派系的选择
三类函数都是从src中读取数据到dst, 他们的不同点在于对EOF的处理, 在io.Copy系和ioutil系中EOF只是读取结束的值, 读到EOF并不返回EOF。io.Read 读到EOF会返回EOF错误。