38

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

func (b *Reader) Peek(n int) ([]byte, error)

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

我需要能够从 Reader 读取特定数量的字节,这将使 reader 前进。基本上,与上面的功能相同,但它使读者进步。有谁知道如何做到这一点?

4

7 回答 7

85

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

n, err := io.ReadFull(reader, p)

即使阅读器被缓冲,这也有效。

于 2013-10-28T23:25:22.970 回答
17
func (b *Reader) Read(p []byte) (n int, err error)

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

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

于 2012-12-01T16:44:47.717 回答
6

TLDR:

my42bytes, err := ioutil.ReadAll(io.LimitReader(myReader, 42))

完整答案:

@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.

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

import (
        "io"
        "io/ioutil"
)

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

这是等效的代码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.
import (
        "io"
)

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

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

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

于 2019-05-15T03:45:16.767 回答
3

我更喜欢 Read() 尤其是如果您要读取任何类型的文件并且它在以块的形式发送数据时也很有用,下面是一个示例来展示它是如何使用的

fs, err := os.Open("fileName"); 

if err != nil{
    fmt.Println("error reading file")
    return
}

defer fs.Close()

reader := bufio.NewReader(fs)

buf := make([]byte, 1024)

for{
    v, _ := reader.Read(buf) //ReadString and ReadLine() also applicable or alternative

    if v == 0{
        return
    }
    //in case it is a string file, you could check its content here...
    fmt.Print(string(buf))
}
于 2013-12-02T18:12:32.757 回答
2

将一个 n 字节大小的缓冲区传递给阅读器。

于 2012-12-01T16:24:24.357 回答
0

如果您想从 an 读取字节io.Reader并进入 an io.Writer,那么您可以使用io.CopyN

CopyN 将 n 个字节(或直到出错)从 src 复制到 dst。它返回复制的字节数和复制时遇到的最早错误。

返回时,写入 == n 当且仅当 err == nil。

written, err := io.CopyN(dst, src, n)
if err != nil {
    // We didn't read the desired number of bytes
} else {
   // We can proceed successfully
}
于 2022-01-17T22:47:19.380 回答
-1

为此,您只需要创建一个字节切片并将数据入此切片

n := 512
buff := make([]byte, n)
fs.Read(buff)  // fs is your reader. Can be like this fs, _ := os.Open('file')

func (b *Reader) Read(p []byte) (n int, err error)

Read 将数据读入 p。它返回读入 p 的字节数。字节最多取自底层 Reader 上的一次读取,因此 n 可能小于 len(p)

于 2016-07-04T06:12:51.063 回答