从golang中的缓冲读取器读取特定的字节数

Kir*_*kus 29 go peek bufferedreader

我知道bufio包中golang的特定功能.

func (b *Reader) Peek(n int) ([]byte, error)
Run Code Online (Sandbox Code Playgroud)

Peek返回接下来的n个字节而不推进读者.字节在下次读取调用时停止有效.如果Peek返回少于n个字节,它也会返回一个错误,解释为什么读取很短.如果n大于b的缓冲区大小,则错误为ErrBufferFull.

我需要能够从读取器读取特定数量的字节,这将推动读者.基本上,与上面的功能相同,但它推动了读者.有人知道怎么做到这一点吗?

小智 71

请注意,该bufio.Read方法io.Read最多调用一次底层,这意味着它可以返回n < len(p),而不会达到EOF.如果您想要准确读取len(p)字节或因错误而失败,您可以io.ReadFull像这样使用:

n, err := io.ReadFull(reader, p)
Run Code Online (Sandbox Code Playgroud)

即使读者被缓冲,这也有效.

  • 这应该是公认的答案.消除了对"短"读取的唠叨怀疑,即无需循环和检查io.EOF等.Doc也有一个很好的例子:https://golang.org/pkg/io/#ReadFull (6认同)
  • 也许值得注意的是io.ReadFull只是此调用的包装器:io.ReadAtLeast(reader,p,len(p))在io.ReadFull的情况下,您应该首先使用它的长度等于您要读取的字节大小,但是对于io.ReadAtLeast而言,p的长度可以是任意长度,只要它大于或等于您要读取的大小即可。 (2认同)

Chr*_*ris 21

func (b *Reader) Read(p []byte) (n int, err error)
Run Code Online (Sandbox Code Playgroud)

http://golang.org/pkg/bufio/#Reader.Read

读取的字节数将限制为 len(p)

  • 但这不会“总是”读取特定数量的字节,它只会将读取的字节限制为 len(p)。 (17认同)

nav*_*aid 5

域名注册地址:

my42bytes, err := ioutil.ReadAll(io.LimitReader(myReader, 42))
Run Code Online (Sandbox Code Playgroud)

完整答案:

@monicuta 提到io.ReadFull哪个效果很好。这里我提供另一种方法。它通过链接ioutil.ReadAllio.LimitReader在一起工作。让我们先阅读文档:

$ go doc ioutil.ReadAll
func ReadAll(r io.Reader) ([]byte, error)
     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. 

$ go doc io.LimitReader
func LimitReader(r Reader, n int64) Reader
     LimitReader returns a Reader that reads from r but stops with EOF after n
     bytes. The underlying implementation is a *LimitedReader.
Run Code Online (Sandbox Code Playgroud)

因此,如果您想从中获取 42 个字节myReader,请执行以下操作

import (
        "io"
        "io/ioutil"
)

func main() {
        // myReader := ...
        my42bytes, err := ioutil.ReadAll(io.LimitReader(myReader, 42))
        if err != nil {
                panic(err)
        }
        //...
}
Run Code Online (Sandbox Code Playgroud)

这是等效的代码 io.ReadFull

$ go doc io.ReadFull
func ReadFull(r Reader, buf []byte) (n int, err error)
    ReadFull reads exactly len(buf) bytes from r into buf. It returns the number
    of bytes copied and an error if fewer bytes were read. The error is EOF only
    if no bytes were read. If an EOF happens after reading some but not all the
    bytes, ReadFull returns ErrUnexpectedEOF. On return, n == len(buf) if and
    only if err == nil. If r returns an error having read at least len(buf)
    bytes, the error is dropped.
Run Code Online (Sandbox Code Playgroud)
import (
        "io"
)

func main() {
        // myReader := ...
        buf := make([]byte, 42)
        _, err := io.ReadFull(myReader, buf)
        if err != nil {
                panic(err)
        }
        //...
}
Run Code Online (Sandbox Code Playgroud)

相比io.ReadFull,一个优点是你不需要手动制作一个buf,其中len(buf)是你要读取的字节数,然后buf在读取时作为参数传递

相反,您只需告诉io.LimitReader您最多需要 42 个字节myReader,然后调用ioutil.ReadAll读取它们,将结果作为字节切片返回。如果成功,返回的切片保证长度为 42。