4

Go语言IO操作 - 1 interface io.Reader

 3 years ago
source link: http://www.pengrl.com/p/20120/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

interface io.Reader 定义

// go/src/io/io.go

type Reader interface {
  Read(p []byte) (n int, err error)
}

interface io.Reader 语义

Reader 中读取数据,存入传入参数 p 中,并通过返回值 n 返回本次读取的大小,以及 err 返回可能存在的错误。

对于一次调用:

可能发生阻塞;不保证读够(读满) len(p) 的数据

  • n 取值范围 0 <= n <= len(p)
  • 即使读取到的数据 n < len(p) ,也不保证 p 内存块后半部分的原始数据保持不变,不被修改
  • 只要有数据可读,即使可读数据 n < len(p) ,也会立即返回,而不是等待读够 len(p) 大小的数据

注意,如果没有数据可读并且也没有错误发生,会阻塞当前协程,直到数据可读或发生错误。

(注意,这里说的阻塞指的是上层代码的表现,Go的IO线程协程调度模型不在本文讨论范围内)

正确处理返回值

可能同时出现 n > 0 并且 err != nil 的情况。

当读取到结尾EOF(end-of-file)时,可以有两种方式

  1. 首次调用返回 n > 0 并且 err != nil
  2. 首次调用返回 n > 0 并且 err == nil

第二次调用返回 n == 0 并且 err == EOF

第一种方式,即使 err != nil ,也有可能读取到了数据。

所以,不管是以上哪种方式,正确处理应该是每次调用结束后,先判断 n ,处理读取到的数据,再判断 err ,像这样:

n, err := r.Read(p)
if n > 0 {
    // ...
    // 注意,此处并没有return等跳过下面判断err值的逻辑
}
if err != nil {
    // ...
}

n == 0 并且 err == nil

  • 正常来说,不应该出现 n == 0 的情况,除非 len(p) == 0
  • n == 0 并且 err == nil 时,应被认为啥事也没发生(一次空调用),而不是EOF

其他

函数调用结束后,内部不会持有 p 的内存

interface io.Reader 举例:

// 1. 读取文件
// go/src/os/file.go
func (f *File) Read(b []byte) (n int, err error) {
  // ...
}

// 2. 读取网络连接
// go/src/net/net.go
type Conn interface {
  Read(p []byte) (n int, err error)
  // ...
}

本文完,作者 yoko ,尊重劳动人民成果,转载请注明原文出处: https://pengrl.com/p/20120/


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK