Go Deep | Blog

Go Deep and Be professional

0%

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

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

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

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

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

TeeReader

TeeReader的描述

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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的用法

官方的源代码示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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)

其输出结果可得:

1
2
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的输出顺序调整一下,如下:

1
2
3
4
5
6
7
//修改前的
printall(tee)
printall(&buf)

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

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

1
some io.Reader stream to be read

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

1
*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.

希望对你有用。

End