标准库提供了io包,里面以流的形式高效的处理数据,不同考虑数据是什么,来自什么地方,发送到哪里,包含io.Writer和io.Reader两个接口,只要实现了对应接口的函数,就可以使用io包中提供的所有功能

Writer和Reader接口

io包围绕着Writer和Reader接口来构建的

内部提供了足够的抽象

首先是io.Writer的声明

type Writer interface {

Writer(p [] byte)(n int,err error)

}

我们展示了io.Writer接口的声明,声明了唯一的方法Writer,就是接受一个byte切片,返回两个值,一个是写入的字节数,一个是err错误值

如果,返回的是 n<len(p)的时候,必须要返回某个非nil的error,

而且,Write不能改写切片中的数据,临时修改也不行

所以Write方法的实现需要能够支持写入传入的byte的全部数据,如果无法写入全部,就返回一个错误

然后是Reader接口的声明

type Reader interface {

Read(p [] byte)(n int,err error)

}

io.Reader接口声明了一个方法Read,接受一个byte,返回两个值,一个值是error错误值,另一个则是读出的数字

对于这个接口,Go的规定如下

第一,如果读到的字节数小于byte切片的长度,那么不要等待新的数据,而是直接返回已读的数据

第二,对于已经到达了可读的末尾的情况,我们可以返回最终的字节数,并且返回EOF作为错误,或者返回nil做为错误值

第三,我们调用Read的时候,如果返回了可读的字节数,先去处理读到的字节,然后处理错误值

第四条,就是不要返回0个可读字节的同时,返回nil作为错误值,如果没有读到值,就返回一个错误

那么我们看一下这些接口和io包的整合使用

使用到了bytes fmt os进行缓冲

拼接和写字符串到stuout

//展示不同的标准款的不同函数如何使用io.Writer接口的

package main

import (

“bytes”

“fmt”

“os”

)

func main() {

// 创建一个Buffer值,将一个字符串写入Buffer

// 实现io.Writer的Write方法

var b bytes.Buffer

b.Write([]byte(“Hello “))

// 传入一个Buffer地址作为io.Writer称为Fprintf的参数

fmt.Fprintf(&b, “World!”)

// 写到标准输出

b.WriteTo(os.Stdout)

}

模拟的标准的输入输出

使用os.stdout来将Hello World写到了终端窗口

比较感兴趣的是Fprintf函数,其函数声明如下

func Fprintf(w io.Writer,format string,a … interface{})(n int,err error)

第一个参数接收一个实现了io.Writer类型的值的地址,

然后我们的Buffer就实现了io.Writer的接口,传入就增加到了Buffer中

最后我们使用writeTo,写到了一个实现io.Write接口的值中

对于os.Stdout的值

var (

Stdin = NewFile(uintptr(syscall.Stdin), “/dev/stdin”)

Stdout = NewFile(uintptr(syscall.Stdout), “/dev/stdout”)

Stderr = NewFile(uintptr(syscall.Stderr), “/dev/stderr”)

)

NewFile返回一个给定的文件描述符和名字的新File

正好实现了io.Write接口

我们利用了都实现了Writer接口,利用标准库中的功能,讲这些组合在一起工作

然后就是利用这些os相关的工具,实现自己的curl工具

我们看下代码如下

//写一个简单版本的curl

package main

import (

“io”

“log”

“net/http”

“os”

)

func main() {

// r是对应的相应,r.Body是io.Reader

r, err := http.Get(os.Args[1])

if err != nil {

log.Fatalln(err)

}

// 创建文件来保存相应

file, err := os.Create(os.Args[2])

if err != nil {

log.Fatalln(err)

}

defer file.Close()

// 合并两个输出设备,进行写操作

dest := io.MultiWriter(os.Stdout, file)

// 读出响应的内容,进行拷贝

io.Copy(dest, r.Body)

if err := r.Body.Close(); err != nil {

log.Println(err)

}

}

基本的curl骨架如下,可以下载展示并保存任何的HTTP Get请求的内容,响应的结果同时写入文件和stdout,在同时写入的方面,我们使用了MultiWriter函数将打开的文件和stdout整合为一个io.Writer值,然后获取值,Copy到了文件和系统输出

利用io包已经提供的支持,以及http和os包已经实现了io.Writer和io.Reader接口类型的实现

解决了curl的问题

我们在io中找到了大量的支持不同功能的函数,通过实现了io.Writer和io.Reader接口类型的值进行调用,了解其可以让我们了解Go语言的设计

发表评论

邮箱地址不会被公开。 必填项已用*标注