126

ファイルに書き込む前にすべてをメモリに保存するのではなく、コンテンツをファイルに直接保存するGoを使用して大きなファイルをダウンロードする方法はありますか?ファイルは非常に大きいため、ファイルに書き込む前にすべてをメモリに保存すると、すべてのメモリが消費されます。

4

4 に答える 4

236

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の本文はリーダーであるため、リーダーを使用する任意の関数を使用して、たとえば、一度にすべてではなく、一度にチャンクを読み取ることができます。この特定のケースでio.Copy()は、あなたのためにうなり声を上げます。

于 2012-07-27T17:50:30.117 に答える
74

スティーブ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
}
于 2015-11-22T10:38:43.267 に答える
16

上記で選択した答えio.Copyはまさに必要なものですが、壊れたダウンロードの再開、ファイルの自動命名、チェックサムの検証、複数のダウンロードの進行状況の監視などの追加機能に関心がある場合は、grabパッケージをチェックアウトしてください。

于 2016-01-19T11:21:30.220 に答える
-7
  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)
        }
    }
}
于 2014-01-25T13:59:02.723 に答える