如何有效地使用Go下载大文件?

有没有办法使用Go下载一个大文件,直接将内容存储到一个文件中,而不是将它存储在内存中,然后再写入文件? 由于文件太大,在将文件写入文件之前将其全部存储在内存中将耗尽所有的内存。

我会假设你的意思是通过http下载(为简洁起见省略了错误检查):

import ("net/http"; "io"; "os") ... out, err := os.Create("output.txt") defer out.Close() ... resp, err := http.Get("http://example.com/") defer resp.Body.Close() ... n, err := io.Copy(out, resp.Body) 

http.Response的Body是一个Reader,所以你可以使用任何带Reader的函数,例如一次读取一个块,而不是一次读取一个块。 在这个特定的情况下, io.Copy()为你做了io.Copy()

史蒂夫M的答案更具描述性的版本。

 import ( "os" "net/http" "io" ) func downloadFile(filepath string, url string) (err error) { // Create the file out, err := os.Create(filepath) if err != nil { return err } defer out.Close() // Get the data resp, err := http.Get(url) if err != nil { return err } defer resp.Body.Close() // Writer the body to file _, err = io.Copy(out, resp.Body) if err != nil { return err } return nil } 

上面使用io.Copyselect的答案正是您所需要的,但是如果您有兴趣了解更多function,例如恢复损坏的下载,自动命名文件,校验和validation或监控多个下载的进度,请检查抓包 。

  1. 这里是一个例子。 https://github.com/thbar/golang-playground/blob/master/download-files.go

  2. 另外我给你一些代码可能会帮助你。

码:

 func HTTPDownload(uri string) ([]byte, error) { fmt.Printf("HTTPDownload From: %s.\n", uri) res, err := http.Get(uri) if err != nil { log.Fatal(err) } defer res.Body.Close() d, err := ioutil.ReadAll(res.Body) if err != nil { log.Fatal(err) } fmt.Printf("ReadFile: Size of download: %d\n", len(d)) return d, err } func WriteFile(dst string, d []byte) error { fmt.Printf("WriteFile: Size of download: %d\n", len(d)) err := ioutil.WriteFile(dst, d, 0444) if err != nil { log.Fatal(err) } return err } func DownloadToFile(uri string, dst string) { fmt.Printf("DownloadToFile From: %s.\n", uri) if d, err := HTTPDownload(uri); err == nil { fmt.Printf("downloaded %s.\n", uri) if WriteFile(dst, d) == nil { fmt.Printf("saved %s as %s\n", uri, dst) } } }