Golang中TeeReader的Writer输出为空的问题小记

  • 更新于 1 8月 2020

这是一个在工作的时候遇到的TeeReaderWriter为空的问题。花了一点时间解决。

并且根据官方示例代码做出一定的调整,发现了一个比较有意思的现象。但是没有什么人说到这个问题。

并且,由于对Golang的流式处理不熟悉,途中遇到了很多的问题。

因此,来对记录一下TeeReader的解读。

TeeReader

TeeReader的描述

首先放出TeeReader的源代码。代码比较简单,如下:

func TeeReader(r Reader, w Writer) Reader { return &teeReader{r, w} } type teeReader struct { r Reader w Writer } func (t *teeReader) Read(p []byte) (n int, err error) { n, err = t.r.Read(p) if n > 0 { if n, err := t.w.Write(p[:n]); err != nil { return n, err } } return }

官方的英文解释如下:

TeeReader returns a Reader that writes to w what it reads from r.

All reads from r performed through it are matched with corresponding writes to w. There is no internal buffering - the write must complete before the read completes.

Any error encountered while writing is reported as a read error.

第一句话对于中文语言者可能没有那么好理解,它的意思其实非常简单:

就是将 r 中的数据读出后同时写入 w 中,然后 teeReader 本身也是可以读取数据的,这样,就相当于复制出了一条数据流。

TeeReader的用法

官方的源代码示例如下:

r := strings.NewReader("some io.Reader stream to be read\n") var buf bytes.Buffer tee := io.TeeReader(r, &buf) printall := func(r io.Reader) { b, err := ioutil.ReadAll(r) if err != nil { log.Fatal(err) } fmt.Printf("%s", b) } printall(tee) printall(&buf)

其输出结果可得:

some io.Reader stream to be read # <= 这个是*io.teeReader some io.Reader stream to be read # <= 这个是*bytes.Buffer

TeeReader为什么Writer为空?

TeeReader的参数是一个reader和一个writer。但是为什么有时候writer会是空的?

这也是我在实际工作中遇到的一个问题。

这里,我们来把源代码示例的printall的输出顺序调整一下,如下:

//修改前的 printall(tee) printall(&buf) //修改过后的 printall(&buf) printall(tee)

这个时候输出即可看到,一个输出结果,也就是:

some io.Reader stream to be read

这个时候如果使用reflect.typeOf()去看他们的输出类型,输出结果为:

*bytes.Buffer: *io.teeReader: some io.Reader stream to be read

因此,可以看得到这里的bytes.Buffer输出内容为空,但是teeReader是不空的。

那么为什么会这样呢?

***A:***其实,这是由于teeReader必须要完成了过后,才会写入到buf当中。因此,提前写诗没有任何数据的。

这个也符合官方原文的英文解释:

TeeReader returns a Reader that writes to w what it reads from r.

希望对你有用。