มีวิธีดาวน์โหลดไฟล์ขนาดใหญ่โดยใช้ 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's Body เป็น Reader ดังนั้นคุณสามารถใช้ฟังก์ชันใด ๆ ที่ใช้ Reader เช่นอ่านทีละชิ้นแทนที่จะอ่านทั้งหมดในครั้งเดียว ในกรณีเฉพาะนี้io.Copy()
จะทำให้คุณพอใจ
client := http.Client{Timeout: 10 * time.Second,} client.Get("http://example.com/")
คำตอบของ 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
}
คำตอบที่เลือกข้างต้นio.Copy
คือสิ่งที่คุณต้องการ แต่หากคุณสนใจในคุณสมบัติเพิ่มเติมเช่นการกลับมาดาวน์โหลดที่เสียการตั้งชื่อไฟล์อัตโนมัติการตรวจสอบความถูกต้องหรือการตรวจสอบความคืบหน้าของการดาวน์โหลดหลายครั้งให้ชำระเงินในแพ็กเกจคว้า
นี่คือตัวอย่าง 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)
}
}
}
ioutil.ReadAll()
. ไม่เป็นไรตราบใดที่คุณจัดการกับไฟล์ขนาดเล็ก
io.Copy
อ่าน 32kb (สูงสุด) จากอินพุตและเขียนลงในเอาต์พุตจากนั้นทำซ้ำ ดังนั้นอย่ากังวลเรื่องความจำ