精确读取n个字节,除非EOF?

时间:2018-09-06 17:32:16

标签: go buffer

我正在使用一个返回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 ,因此如果ErrUnexpectedEOF无法填充2048个字节的原因是,则不会返回buf该文件是EOF后例如500字节但是,在任何其他情况下,如果出现问题,都应返回ErrUnexpectedEOF

我该怎么做?

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

1 个答案:

答案 0 :(得分: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
    }
}