【问题标题】:Read exactly n bytes unless EOF?准确读取 n 个字节,除非 EOF?
【发布时间】:2018-09-07 04:30:39
【问题描述】:

我正在使用返回 io.Reader 的函数从 Internet 下载文件。

我想以精确的 2048 个块处理文件,直到由于 EOF 而不再可能。

io.ReadFull 函数几乎就是我想要的:

buf := make([]byte, 2048)

for {
    if _, err := io.ReadFull(reader, buf); err == io.EOF {
        return io.ErrUnexpectedEOF
    } else if err != nil {
        return err
    }

    // Do processing on buf
}

问题在于并非所有文件都是 2048 字节的倍数,因此最后一个块可能只是例如500 字节,io.ReadFull 将因此返回 ErrUnexpectedEOF 并且最后一个块被丢弃。

总结我想要的函数名称可能是io.ReadFullUnlessLastChunk,所以如果buf不能用2048字节填充,则不会返回ErrUnexpectedEOF,是文件是EOF 之后,例如500 字节。但是,在任何其他情况下,ErrUnexpectedEOF 应在出现问题时返回。

我该怎么做才能做到这一点?

另一个问题是直接从网络读取 2048 字节似乎有很多开销,如果我可以从网络获取 256 KB 到缓冲区,然后从该缓冲区获取我需要的 2048 字节,那会更好。

【问题讨论】:

  • io.LimitReader 对你不起作用有什么原因吗?
  • ReadFull() 不会丢弃最后一个块。它读取剩余数据但也返回 EOF 错误。
  • 你似乎知道你想要的确切行为,这不是一个典型的用例——为什么不直接实现只需要很少几行代码的功能呢?
  • @BillSmith124:您可以单击文档中的函数,它会显示源代码(或在您使用的任何编辑器中转到定义):golang.org/src/io/io.go?s=10817:10883#L294 - 只需删除不需要的条件。
  • @BillSmith124:是什么给了你这样的印象?

标签: go buffer


【解决方案1】:

例如,

package main

import (
    "bufio"
    "fmt"
    "io"
    "os"
)

func readChunks(r io.Reader) error {
    if _, ok := r.(*bufio.Reader); !ok {
        r = bufio.NewReader(r)
    }
    buf := make([]byte, 0, 2048)
    for {
        n, err := io.ReadFull(r, buf[:cap(buf)])
        buf = buf[:n]
        if err != nil {
            if err == io.EOF {
                break
            }
            if err != io.ErrUnexpectedEOF {
                return err
            }
        }

        // Process buf
        fmt.Println(len(buf))

    }
    return nil
}

func main() {
    fName := `test.file`
    f, err := os.Open(fName)
    if err != nil {
        fmt.Println(err)
        return
    }
    defer f.Close()

    err = readChunks(f)
    if err != nil {
        fmt.Println(err)
        return
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-22
    • 2021-04-09
    • 2018-06-28
    • 2019-09-13
    • 2020-06-12
    • 2015-02-17
    • 2017-12-12
    • 1970-01-01
    相关资源
    最近更新 更多