Есть ли способ загрузить большой файл с помощью Go, который будет хранить содержимое непосредственно в файле, а не хранить его все в памяти, прежде чем записывать его в файл? Поскольку файл настолько велик, чтобы сохранить его все в памяти, прежде чем записывать его в файл, он будет использовать всю память.
Как я могу эффективно загрузить большой файл с помощью Go?
Ответ 1
Я предполагаю, что вы имеете в виду загрузку через 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 является Reader, поэтому вы можете использовать любые функции, которые берут Reader, например, читайте кусок одновременно, а не все сразу. В этом конкретном случае io.Copy()
выполняет gruntwork для вас.
Ответ 2
Более описательная версия ответа Стива М.
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
}
Ответ 3
Ответ, выбранный выше, с использованием io.Copy
- это именно то, что вам нужно, но если вас интересуют дополнительные функции, такие как возобновление сломанных загрузок, автоматическое присвоение имен файлам, проверка контрольной суммы или мониторинг выполнения нескольких загрузок, проверка grab.
Ответ 4
-
Вот пример. https://github.com/thbar/golang-playground/blob/master/download-files.go
-
Также я даю вам некоторые коды, которые могут вам помочь.
код:
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)
}
}
}