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

Cor*_*ory 101 go

有没有办法使用Go下载大文件,将内容直接存储到文件中,而不是在将其写入文件之前将其全部存储在内存中?因为文件太大,所以在将文件写入文件之前将其全部存储在内存中会耗尽所有内存.

Ste*_*e M 206

我假设你的意思是通过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)
Run Code Online (Sandbox Code Playgroud)

http.Response的Body是一个Reader,因此您可以使用任何带有Reader的函数,例如一次读取一个块而不是一次读取一个块.在这个特定的情况下,io.Copy()你的gruntwork.

  • 请注意,`io.Copy`从输入读取32kb(最大值)并将它们写入输出,然后重复.所以不要担心记忆. (80认同)
  • 您可以使用它在给定超时后取消下载 ```client := http.Client{Timeout: 10 * time.Second,} client.Get("http://example.com/") ``` (2认同)

Pab*_*mer 47

史蒂夫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()

  // Check server response
  if resp.StatusCode != http.StatusOK {
    return fmt.Errorf("bad status: %s", resp.Status)
  }

  // Writer the body to file
  _, err = io.Copy(out, resp.Body)
  if err != nil  {
    return err
  }

  return nil
}
Run Code Online (Sandbox Code Playgroud)


小智 11

上面选择的答案io.Copy正是您所需要的,但如果您对其他功能感兴趣,例如恢复损坏的下载,自动命名文件,校验和验证或监控多次下载的进度,请查看抓包.