go - Golang ioutil.ReadAll无尽循环

标签 go

我是Golang的新手。

我试图了解如何使用ioutil.ReadAll(非HTTP响应)。根据源代码(和文档):

// ReadAll reads from r until an error or EOF and returns the data it read.
// A successful call returns err == nil, not err == EOF. Because ReadAll is
// defined to read from src until EOF, it does not treat an EOF from Read
// as an error to be reported.
func ReadAll(r io.Reader) ([]byte, error) {
    return readAll(r, bytes.MinRead)
}

在此示例中,我已经在此处实现了io.Reader(在Go Playground上也为here):
// go version go1.13.5 darwin/amd64

package main

import (
    "bytes"
    "fmt"
    "io/ioutil"
)

// Thing contains a body
type Thing struct {
    Body []byte
}

// Read reads from body into p
func (t Thing) Read(dst []byte) (n int, err error) {
    // Note: bytes.Reader does return io.EOF
    // https://golang.org/src/bytes/reader.go?s=1154:1204#L30
    reader := bytes.NewReader(t.Body)
    return reader.Read(dst)
}

func main() {
    fmt.Println("Testing bytes")

    thing := new(Thing)
    thing.Body = []byte("Hello World")

    fmt.Println("thing.Body:", string(thing.Body))

    // This works
    buf := make([]byte, len(thing.Body))
    n, err := thing.Read(buf)
    fmt.Println("Amount read:", n)
    if err != nil {
        fmt.Println("Error: ", err)
    }
    fmt.Println("buf:", string(buf))

    // ReadAll runs forever....why?
    buf2, err := ioutil.ReadAll(thing)
    if err != nil {
        fmt.Println("Error:", err)
    }
    fmt.Println("buf2:", buf2)

}

上面,Read实现工作正常。它只是调用bytes.NewReader()并从中读取。但是,在结构上使用ioutil.ReadAll时,它将永远运行(超时),我不明白为什么。最初我以为那里可能没有EOF,但是字节读取器source code确实在这里返回io.EOF:
// Read implements the io.Reader interface.
func (r *Reader) Read(b []byte) (n int, err error) {
    if r.i >= int64(len(r.s)) {
        return 0, io.EOF
    }
    r.prevRune = -1
    n = copy(b, r.s[r.i:])
    r.i += int64(n)
    return
}

我已经在http响应主体上看到了此方法的其他实现,在这些实现中,它们必须在读取主体后明确关闭主体,但是我看不到字节读取器上的任何方法来关闭主体。

有人可以帮助我了解这种情况下的情况吗?提前致谢。

最佳答案

每次调用bytes.Reader时,您都在创建一个新的Thing.Read()。每次获取相同的11个字节时,ReadAll()都会继续调用Thing.Read()函数。

从您的评论中,我认为您只想创建一次,例如,在“构造函数”中,您无需存储Body,因为它存储在Bytes.Reader中。

type Thing struct {
    r io.Reader
}

func NewThing(s string) (t Thing) {
    t.r = bytes.NewReader([]byte(s))
    return
}

func (t Thing) Read(dst []byte) (n int, err error) {
    return t.r.Read(dst)
}

但是Thing只是io.Reader的包装,没有任何用途。您也可以直接使用“io.Reader”。
    buf2, err := ioutil.ReadAll(bytes.NewReader([]byte("Hello World")))

关于go - Golang ioutil.ReadAll无尽循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61599019/

相关文章:

go - 如何在两个自定义类型之间进行转换

mysql - 在 mysql 上使用多个 goroutine 进行不同的操作

go - 如何使用 "crypto/rand"包生成随机整数?

go - 简单的 Web 服务器实现 : GoLang

golang 使用嵌入式模板 : too few values in struct initializer 初始化结构

parsing - Go时间解析返回不同的值

go - 在 golang boringssl 中验证 FIPS 模式

go - 除了可移植性和安全性原因之外,为什么有人想通过 WebAssembly 在 Web 浏览器中运行他们现有的 go/rust/c++ 应用程序?

arrays - slice 内的数组

go - 为什么调用OpenFile时需要设置权限?