golang中各种io花式读写方法

3,537 阅读2分钟

在上一篇里我们详细的看了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错误。