Go编程技巧--io.Reader/Writer

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go编程技巧--io.Reader/Writer相关的知识,希望对你有一定的参考价值。

参考技术A Go 原生的 pkg 中有一些核心的 interface ,其中 io.Reader/Writer 是比较常用的接口。很多原生的结构都围绕这个系列的接口展开,在实际的开发过程中,你会发现通过这个接口可以在多种不同的io类型之间进行过渡和转化。本文结合实际场景来总结一番。

围绕 io.Reader/Writer ,有几个常用的实现:

这些实现对于初学者来说其实比较难去记忆,在遇到实际问题的时候更是一脸蒙圈,不知如何是好。下面用实际的场景来举例

encoding/base64 包中:

这个用来做 base64 编码,但是仔细观察发现,它需要一个io.Writer作为输出目标,并用返回的 WriteCloser 的Write方法将结果写入目标,下面是Go官方文档的例子

这个例子是将结果写入到 Stdout ,如果我们希望得到一个字符串呢?观察上面的图,不然发现可以用bytes.Buffer作为目标 io.Writer :

这种场景经常用在基于字节的协议上,比如有一个具有固定长度的结构:

通过一个 []byte 来反序列化得到这个 Protocol ,一种思路是遍历这个 []byte ,然后逐一赋值。其实在 encoding/binary 包中有个方便的方法:

这个方法从一个 io.Reader 中读取字节,并已 order 指定的端模式,来给填充 data (data需要是fixed-sized的结构或者类型)。要用到这个方法首先要有一个 io.Reader ,从上面的图中不难发现,我们可以这么写:

换句话说,我们将一个 []byte 转成了一个 io.Reader 。

反过来,我们需要将 Protocol 序列化得到 []byte ,使用 encoding/binary 包中有个对应的 Write 方法:

通过将 []byte 转成一个 io.Writer 即可:

比如对于常见的基于文本行的 HTTP 协议的读取,我们需要将一个流按照行来读取。本质上,我们需要一个基于缓冲的读写机制(读一些到缓冲,然后遍历缓冲中我们关心的字节或字符)。在Go中有一个 bufio 的包可以实现带缓冲的读写:

这个ReadString方法从 io.Reader 中读取字符串,直到 delim ,就返回 delim 和之前的字符串。如果将 delim 设置为 \n ,相当于按行来读取了:

等价于

base64编码io.Reader

有没有办法获取包含二进制数据的io.Reader,并将其读出base64编码。

我在编码/ base64中看到了

func NewDecoder(enc *Encoding, r io.Reader) io.Reader

但是假设io.Reader数据是base64并返回一个io.Reader来将其解码为二进制。

func NewEncoder(enc *Encoding, w io.Writer) io.WriteCloser

返回一个io.Writer来将二进制编码为base64,但是我需要使用go-aws-sdk s3manage上传器,它需要一个io.Reader接口。

uploader := s3manager.NewUploaderWithClient(svc)
_, err := uploader.Upload(&s3manager.UploadInput{
   Bucket: aws.String(bucket),
  Key:    aws.String(key),
  Body:   input,
})

输入需要实现io.Reader接口

数据很大,所以我不想在进行编码之前将输入完全读入内存

答案

Pipe的概念用于将读者更改为Writers,反之亦然。

使用io.Pipe,您可以将源io.Reader复制到编码器中,并将io.PipeReader作为要上传的正文传递。

如果你想通过它,错误处理有点不寻常,但可以使用CloseWithError方法。确保您还记下关闭管道和编码器的正确顺序。

source := strings.NewReader("Hello, World!")

pr, pw := io.Pipe()
encoder := base64.NewEncoder(base64.StdEncoding, pw)

go func() {
    _, err := io.Copy(encoder, source)
    encoder.Close()

    if err != nil {
        pw.CloseWithError(err)
    } else {
        pw.Close()
    }
}()

https://play.golang.org/p/qvc1f7kyTeP

以上是关于Go编程技巧--io.Reader/Writer的主要内容,如果未能解决你的问题,请参考以下文章

golang中的io.Reader/Writer

Go标准库-带缓冲的IO(bufio)

GO语言ioutil包

Java IO: Reader和Writer

golang 中通过strings/bytes/bufio 等包实现相关IO

go 学习之fmt包