我正在使用返回 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/