io

[TOC]

io.Writer interface

type Writer interface {
                Write(p []byte) (n int, err error)
}
  • byte slice 在Write方法中不能被改变
  • 0 <= n <= len(p)
  • 实现该接口的原则:https://golang.org/pkg/io/#Writer

io.Reader

  • 参考:
    • https://tour.golang.org/methods/21
type Reader interface {
        Read(p []byte) (n int, err error)
}
  • 读取最多 len(p) bytes
  • 0 <= n <= len(p)
  • Read() 触发return的情况(测试地址:tour of reader):
    • cap(p) < len(data), 函数返回情况n>0, err=nil: 一次读取达到了p的cap,这种情况下要循环全部读取,可以用ioutil.ReadAll() 读取全部。
    • cap(p) > len(data), 函数返回情况n = len(data)(n>0), err = nil: 一次就全部读取了数据,此时err是nil,第二次调用时,返回0, err = EOF。
    • cap(p) > len(data), 函数返回情况n = len(data)(n>0), err = EOF: 场景还未见过
    • Reader已经处于EOF状态
  • 实现该接口原则: https://golang.org/pkg/io/#Reader
    • 不允许存在 n=0 & err = nil的情况
    • 参考已经实现的例子: https://golang.org/pkg/io/#CopyBuffer

io.Copy vs ioutil.ReadAll() vs copy

ioutil.ReadAll()

  • 源码调用的关系如下:
    io.util.ReadAll() --> readAll(r, bytes.MinRead) --> bytes.Buffer.ReadFrom(r) --> for 循环读取,每次读取时Buffer.grow(bytes.MinRead)
  • 原理:内部用Buffer存数据,每次读取bytes.MinRead(512)字节
  • 数据流: Reader --> []byte(Buffer)

io.Copy

  • 源码调用关系如下: Copy(dst, src) --> copyBuffer(dst, src, buf) --> 循环读取,并写入到dst 中
  • 原理:
    1. 申请一个缓存buf,buf可以由调用方提供,也可以传nil,内部创建32 K的缓存大小。
    2. 循环读取缓存大小的数据,并写入到dst中,直到读取结束
  • 数据流程: Reader --> [N]byte --> Writer

copy

copy 不适用于io场景,copy用于slice 间的拷贝

对比

  • 从数据流来看,io.Copy 多一次复制而且还要多申请一份空间,但是每次可读取大小默认32K
  • ioutil.ReaddAll 使用Buffer管理内存增长,每次增长 MinREad(0.5K) 字节,如果Reader的数据很大,ioutil Buffer会变得很大,要注意使用
  • 使用场景:io.Copy 适合大数据场景读取,ioutil.ReadAll 适合小数据量读取,一般常用的后端服务可以用ioutil.ReadAll 来处理。

你可能感兴趣的:(io)