go - 除非 EOF,否则只读取 n 个字节?

标签 go buffer

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

我想以正好 2048 个 block 的形式处理文件,直到由于 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 字节的倍数,因此最后一个 block 可能只是例如500 字节,io.ReadFull 将因此返回 ErrUnexpectedEOF 并丢弃最后一个 block 。

总结我想要的函数名可以是io.ReadFullUnlessLastChunk,所以ErrUnexpectedEOF不会因为buf不能返回填充了 2048 字节,是文件在 e.g. 之后是 EOF 500 字节。但是,在任何其他情况下,ErrUnexpectedEOF 都应在发生问题时返回。

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

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

最佳答案

例如,

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
    }
}

关于go - 除非 EOF,否则只读取 n 个字节?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52209430/

相关文章:

javascript - 二进制和utf8有什么区别?

xml - 解码 XML

go - 如何修复 `can' t 在 helm 中的 _helpers.tpl 中评估类型接口(interface) {}` 中的字段 extraHosts

angular - 无法导出 'Buffer' 。只能从模块导出本地声明

vim - vim 中的缓冲区和寄存器有什么区别?

c - 如何读取大文件(最多 2 000 000 000 个字符)并存储它们

go - 加入或推送 slice

bash - 检查 Golang 中是否存在二进制文件

go - 获取 syslog.Writer undefined

.net - 使用 .net 托管代码对命令窗口进行屏幕抓取