猿问

Golang ioutil.ReadAll 无限循环

我是 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 上):


// 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)


}

上面,读取实现工作正常。它只是调用 bytes.NewReader() 并从中读取。但是,在结构上使用 ioutil.ReadAll 时,它会永远运行(超时),我不明白为什么。最初我认为那里可能没有 EOF,但是字节阅读器源代码确实在此处返回 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 响应主体上看到了其他实现,他们在阅读主体后明确地必须关闭主体,但我没有看到字节阅读器上的任何方法来关闭它。


有人可以帮助我了解在这种情况下发生了什么吗?提前致谢。


尚方宝剑之说
浏览 90回答 1
1回答

潇湘沐

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")))
随时随地看视频慕课网APP

相关分类

Go
我要回答