Go标准库笔记Ⅰ:IO



io:基本的I/O接口

Reader接口

  • 定义:

    1
    2
    3
    
    type Reader interface{
        Read(p []byte)(n int,err error)
    }
  • Read方法将len(p)个字节读取到p中,返回值是读取的字节数和任何遇到的错误,这个错误可能是读取中遇到的意外或者EOF(end-of-file)。

  • Read方法返回错误时,不代表没有读取到任何数据。调用者应该处理返回的任何数据,之后才处理可能的错误

  • 即使Read函数返回的的字节数小于p的长度,函数也会返回完整的p;如果读取的数据不到p的最大长度,Read方法会返回当前读取到的可用数据,不会继续等待读取。

  • 因为所有实现了Read方法的类型都相当于实现了io.Reader接口,也就是说,在所有需要io.Reader的地方,可以传递实现了Read()方法的类型的实例。

  • Example:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    
    func ReadFrom(reader io.Reader,num int)([]byte,error){
        p := make([]byte,num)    //创建长度为num的byte数组
        n, err := reader.Read(p)    //将reader中的数据读到p里面
        if n > 0{
            return p[:n],nil
        }
        return p ,err
    }
    
    // 从标准输入读取
    data, err = ReadFrom(os.Stdin, 11)
    
    // 从普通文件读取,其中 file 是 os.File 的实例
    data, err = ReadFrom(file, 9)
    
    // 从字符串读取
    data, err = ReadFrom(strings.NewReader("from string"), 12)

    Writer接口

  • 定义:

    1
    2
    3
    
    type Write interface{
        Write(p []byte)(n ,int,err error)
    }
  • 所有实现了Write方法的类型都实现了io.Write接口。

  • Write方法将len(p)个字节写入基本数据流(也就是传递数据的io实例,例如os.Stdouthttp.ResponseWriter),返回写入的字节数以及遇到的任何错误,不同的是,Write返回的字节数小于p的长度时,必须返回一个非nil的错误。

  • 参考文章:《以io.Writer为例看go中的interface{}》

举例实现了io.Reader接口或io.Writer接口的标准库类型

  • 一个能查看接口所有的实现类型的官网镜像:http://docs.studygolang.com
  • 举例一些标准库类型
    • os.File同时实现了io.Readerio.Writer接口
    • strings.Reader
    • bufio.Reader/Writer
    • bytes.Buffer同时实现了io.Readerio.Writer
    • bytes.Reader
    • compress/gzip.Reader/Writer
    • crypto/cipher.StreamReader/StreamWriter
    • crypto/tls.Conn同时实现了io.Readerio.Writer
    • encoding/csv.Reader/Writer
    • mime/multipart.Part 实现了io.Reader
    • net/conn分别实现了io.Readerio.Writer(Conn接口定义了Read/Write)

ReaderAtWriterAt接口

  • 定义:

    1
    2
    3
    4
    5
    6
    
    type ReaderAt interface{
        ReadAt(p []byte, off int64) (n int, err error)
    }
    type WriterAt interface {
        WriteAt(p []byte, off int64) (n int, err error)
    } 
  • ReadAt()WriteAt()方法多了一个参数off int64,这个参数表示偏移量。实现的功能是从该制定的偏移量处读取/写入。

  • ReadAt()方法比Read()方法严格一些,当返回的字节数小于p的长度时,必须要返回一个非nil的错误,通知调用方。

  • Example:

    1
    2
    3
    4
    5
    6
    7
    
    reader := strings.NewReader("Go标准库")
    p := make([]byte,9)
    n, err := reader.ReadAt(p,2)
    if err != nil{
        panic(err)
    }
    fmt.Printf("%s,%d\n",p,n)

    输出:

    1
    
    标准库,9

    注意:需要知道的是,如果上面代码中改成p := make([]byte,10)将会触发panic,输出panic: EOF,这就可以看出ReadAt比Read严格的错误机制了。

  • WriteAt方法基本一致,但是在写入的时候,会将从offset处开始到写入内容长度相同的这一段内容覆盖掉,举例:

    1
    2
    3
    
    // file是一个.txt文件,里面的内容是“Golang中文社区——这里是多余的”
    n,err := file.WriteAt([]byte("Go语言中文网"),24)
    //最终file中的内容变成了“Golang中文社区——Go语言中文网”,也就是从offset=24处写入的内容,将之前的内容覆盖掉了

    ReaderFromWriterTo接口

  • 定义:

    1
    2
    3
    
    type ReadFrom interface{
        ReadFrom(r Reader)(n int64,err error)
    }
  • ReadFrom方法从一个reader中读取数据,读取到文件末尾(EOF)或者发生错误是进行返回,返回读取的字节数,还有发生的错误,或者io.EOF