我们读取http应答通常用:
ioutil.ReadAll(resp.Body)
很好用也很方便,但是如果应答的包很大时(下载文件),不仅会分配很大的内存而且慢。
所以我们需要分批读取,每次读取一块直到所有应答读取完成。
代码如下:
func ReadChunk(r io.Reader, maxChunkSize int, chanChunk chan<- []byte) {
for {
buf := make([]byte, maxChunkSize)
n, err := r.Read(buf)
if n < 0 {
break
}
if err != nil && err != io.EOF {
break
}
chanChunk <- buf[:n]
if err == io.EOF {
break
}
}
close(chanChunk)
}
- 注意当读到io.EOF时不能立马退出,它还是会返回一部分数据的;
- 用chan的好处是可以单独开启goroutine下载,一边读一边写;
如下,可以这样处理数据:
chanChunk := make(chan []byte, 5)
go ReadChunk(resp.Body, maxUploadSize/2, chanChunk)
total := 0
for chunk := range chanChunk {
total += len(chunk)
goutil.PanicIfErr(goutil.WriteFileAppend(to, chunk))
fmt.Printf("\r%d %s\t", total, goutil.FormatBytes(float64(total)))
}