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

时间:2012-07-27 17:38:52

标签: go

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

4 个答案:

答案 0 :(得分:198)

我假设您的意思是通过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()为您做了笨拙的工作。

答案 1 :(得分:44)

Steve 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
}

答案 2 :(得分:10)

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

答案 3 :(得分:-6)

  1. 以下是一个示例。 https://github.com/thbar/golang-playground/blob/master/download-files.go

  2. 我也给你一些代码可以帮到你。

  3. 代码:

    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)
            }
        }
    }