如何从同一个 io.Reader 中读取多次
How to read multiple times from same io.Reader
我想使用包含图像的 request.Body(type io.ReadCloser)
。
我不想使用 ioutil.ReadAll()
因为我想将这个正文直接写入文件并解码它,所以我只想使用对内容的引用来传递给进一步的功能电话,
我尝试创建 reader 的多个实例,如下所示
package main
import (
"io/ioutil"
"log"
"strings"
)
func main() {
r := strings.NewReader("some io.Reader stream to be read\n")
a := &r
b := &r
log.Println(ioutil.ReadAll(*a))
log.Println(ioutil.ReadAll(*b))
}
但在第二次调用中它总是导致 nil
。
请帮助我如何为同一个 reader 传递多个单独的引用?
当您调用 ReadAll
时,它会清空缓冲区,因此第二次调用总是 return 什么都没有。您可以做的是保存 ReadAll
的结果并在您的函数中重用它。例如:
bytes, _ := ioutil.ReadAll(r);
log.Println(string(bytes))
从技术上讲,在一个 reader 上,您不能多次阅读。
- 即使您创建了不同的引用但是
- 当您阅读一次时,所有引用都将引用同一对象。
- 所以您可以做的是读取内容并将其存储在一个变量中。
- 然后根据需要多次使用该变量。
这将打印两次。
package main
import (
"io/ioutil"
"log"
"strings"
)
func main() {
r := strings.NewReader("some io.Reader stream to be read\n")
stringData, _ := ioutil.ReadAll(r)
log.Println(stringData)
log.Println(stringData)
}
io.Reader
被视为流。因此,您无法阅读它两次。想象一下传入的 TCP 连接 - 您无法倒带传入的内容。
但您可以使用 io.TeeReader
复制流:
package main
import (
"bytes"
"io"
"io/ioutil"
"log"
"strings"
)
func main() {
r := strings.NewReader("some io.Reader stream to be read\n")
var buf bytes.Buffer
tee := io.TeeReader(r, &buf)
log.Println(ioutil.ReadAll(tee))
log.Println(ioutil.ReadAll(&buf))
}
编辑: 正如@mrclx 指出的:您需要先从 TeeReader
读取,否则缓冲区将为空。
当您从 ioutil.ReadAll(r) 读取时,内容消失了。你不能再读一遍。
例如:
var response *http.Response
//Read the content
rawBody, err := ioutil.ReadAll(response.Body)
if err != nil {
t.Error(err)
}
// Restore the io.ReadCloser to it's original state
response.Body = ioutil.NopCloser(bytes.NewBuffer(rawBody))
我想使用包含图像的 request.Body(type io.ReadCloser)
。
我不想使用 ioutil.ReadAll()
因为我想将这个正文直接写入文件并解码它,所以我只想使用对内容的引用来传递给进一步的功能电话,
我尝试创建 reader 的多个实例,如下所示
package main
import (
"io/ioutil"
"log"
"strings"
)
func main() {
r := strings.NewReader("some io.Reader stream to be read\n")
a := &r
b := &r
log.Println(ioutil.ReadAll(*a))
log.Println(ioutil.ReadAll(*b))
}
但在第二次调用中它总是导致 nil
。
请帮助我如何为同一个 reader 传递多个单独的引用?
当您调用 ReadAll
时,它会清空缓冲区,因此第二次调用总是 return 什么都没有。您可以做的是保存 ReadAll
的结果并在您的函数中重用它。例如:
bytes, _ := ioutil.ReadAll(r);
log.Println(string(bytes))
从技术上讲,在一个 reader 上,您不能多次阅读。
- 即使您创建了不同的引用但是
- 当您阅读一次时,所有引用都将引用同一对象。
- 所以您可以做的是读取内容并将其存储在一个变量中。
- 然后根据需要多次使用该变量。
这将打印两次。
package main
import (
"io/ioutil"
"log"
"strings"
)
func main() {
r := strings.NewReader("some io.Reader stream to be read\n")
stringData, _ := ioutil.ReadAll(r)
log.Println(stringData)
log.Println(stringData)
}
io.Reader
被视为流。因此,您无法阅读它两次。想象一下传入的 TCP 连接 - 您无法倒带传入的内容。
但您可以使用 io.TeeReader
复制流:
package main
import (
"bytes"
"io"
"io/ioutil"
"log"
"strings"
)
func main() {
r := strings.NewReader("some io.Reader stream to be read\n")
var buf bytes.Buffer
tee := io.TeeReader(r, &buf)
log.Println(ioutil.ReadAll(tee))
log.Println(ioutil.ReadAll(&buf))
}
编辑: 正如@mrclx 指出的:您需要先从 TeeReader
读取,否则缓冲区将为空。
当您从 ioutil.ReadAll(r) 读取时,内容消失了。你不能再读一遍。 例如:
var response *http.Response
//Read the content
rawBody, err := ioutil.ReadAll(response.Body)
if err != nil {
t.Error(err)
}
// Restore the io.ReadCloser to it's original state
response.Body = ioutil.NopCloser(bytes.NewBuffer(rawBody))