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

huangapple go评论77阅读模式
英文:

Reading specific number of bytes from a buffered reader in golang

问题

我知道bufio包中的特定函数。

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

> Peek函数返回下一个n个字节,但不会推进读取器。这些字节在下一次读取调用时将不再有效。如果Peek返回的字节数少于n个,它还会返回一个解释读取不完整的错误。如果n大于b的缓冲区大小,则错误为ErrBufferFull。

我需要能够从Reader中读取特定数量的字节,并推进读取器。基本上,与上面的函数相同,但它会推进读取器。有人知道如何实现这个吗?

英文:

I am aware of the specific function in golang from the bufio package.

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

> Peek returns the next n bytes without advancing the reader. The bytes
> stop being valid at the next read call. If Peek returns fewer than n
> bytes, it also returns an error explaining why the read is short. The
> error is ErrBufferFull if n is larger than b's buffer size.

I need to be able to read a specific number of bytes from a Reader that will advance the reader. Basically, identical to the function above, but it advances the reader. Does anybody know how to accomplish this?

答案1

得分: 87

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

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

即使读取器是带缓冲的,这种方法也适用。

英文:

Note that the bufio.Read method calls the underlying io.Read at most once, meaning that it can return n &lt; len(p), without reaching EOF. If you want to read exactly len(p) bytes or fail with an error, you can use io.ReadFull like this:

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

This works even if the reader is buffered.

答案2

得分: 17

函数(方法)(b *Reader)Read(p []byte)(n int,err error)

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

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

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

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

The number of bytes read will be limited to len(p)

答案3

得分: 9

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从r中读取直到出现错误或EOF并返回它读取的数据成功的调用返回err == nil而不是err == EOF因为ReadAll被定义为从src读取直到EOF所以它不会将来自Read的EOF视为要报告的错误

$ go doc io.LimitReader
func LimitReader(r Reader, n int64) Reader
     LimitReader返回一个从r读取但在读取n个字节后停止并返回EOF的Reader底层实现是*LimitedReader

所以如果你想从myReader中获取42个字节,你可以这样做:

import (
        "io"
        "io/ioutil"
)

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

下面是使用io.ReadFull的等效代码:

import (
        "io"
)

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

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

相反,你只需告诉io.LimitReader你最多想从myReader中读取42个字节,并调用ioutil.ReadAll将它们全部读取,将结果作为字节切片返回。如果成功,返回的切片的长度保证为42。

英文:

TLDR:

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

Full answer:

@monicuta mentioned io.ReadFull which works great. Here I provide another method. It works by chaining ioutil.ReadAll and io.LimitReader together. Let's read the doc first:

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

So if you want to get 42 bytes from myReader, you do this

import (
        &quot;io&quot;
        &quot;io/ioutil&quot;
)

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

Here is the equivalent code with 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 (
        &quot;io&quot;
)

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

Compared to io.ReadFull, an advantage is that you don't need to manually make a buf, where len(buf) is the number of bytes you want to read, then pass buf as an argument when you Read

Instead you simply tell io.LimitReader you want at most 42 bytes from myReader, and call ioutil.ReadAll to read them all, returning the result as a slice of bytes. If successful, the returned slice is guaranteed to be of length 42.

答案4

得分: 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和ReadLine()也适用或可替代
	
	if v == 0{
		return
	}
	//如果是字符串文件,你可以在这里检查它的内容...
	fmt.Print(string(buf))
}
英文:

I am prefering Read() especially if you are going to read any type of files and it could be also useful in sending data in chunks, below is an example to show how it is used

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

if err != nil{
	fmt.Println(&quot;error reading file&quot;)
	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))
}

答案5

得分: 1

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

英文:

Pass a n-bytes sized buffer to the reader.

答案6

得分: 0

如果你想从io.Reader中读取字节并写入io.Writer,那么你可以使用io.CopyN

> CopyN从src复制n个字节(或直到出现错误)到dst。它返回复制的字节数和在复制过程中遇到的最早的错误。
>
> 返回时,只有在err == nil时,written == n。

written, err := io.CopyN(dst, src, n)
if err != nil {
    // 我们没有读取到期望的字节数
} else {
   // 我们可以成功进行下一步操作
}

<details>
<summary>英文:</summary>

If you want to read the bytes from an `io.Reader` and into an `io.Writer`, then you can use [`io.CopyN`](https://pkg.go.dev/io#CopyN)

&gt; CopyN copies n bytes (or until an error) from src to dst. It returns the number of bytes copied and the earliest error encountered while copying.
&gt;
&gt; **On return, written == n if and only if err == nil.**

```go
written, err := io.CopyN(dst, src, n)
if err != nil {
    // We didn&#39;t read the desired number of bytes
} else {
   // We can proceed successfully
}

</details>



# 答案7
**得分**: -1

要做到这一点,您只需要创建一个字节切片,并使用以下代码将数据读入该切片中:

    n := 512
    buff := make([]byte, n)
    fs.Read(buff)  // fs是您的读取器。可以像这样 fs, _ := os.Open('file')


`func (b *Reader) Read(p []byte) (n int, err error)`
&gt; Read将数据读入p中。它返回读入p的字节数。
&gt; 字节来自底层读取器上的最多一个Read操作,
&gt; 因此n可能小于len(p)


  [1]: https://golang.org/pkg/bufio/#Reader.Read

<details>
<summary>英文:</summary>

To do this you just need to create a byte slice and [read][1] the data into this slice with

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


----------


`func (b *Reader) Read(p []byte) (n int, err error)`
&gt; Read reads data into p. It returns the number of bytes read into p.
&gt; The bytes are taken from at most one Read on the underlying Reader,
&gt; hence n may be less than len(p)


  [1]: https://golang.org/pkg/bufio/#Reader.Read

</details>



huangapple
  • 本文由 发表于 2012年12月1日 23:29:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/13660864.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定