普通文件下载
package main
import (
"io"
"net/http"
"os"
)
func main() {
// 下载地址:
fileUrl := "http://xxxxxx.com/files/"
if err := DownloadFile("保存文件名.png", fileUrl); err != nil {
panic(err)
}
}
// download file会将url下载到本地文件,它会在下载时写入,而不是将整个文件加载到内存中。
func DownloadFile(filepath string, url string) error {
// Get the data
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
// Create the file
out, err := os.Create(filepath)
if err != nil {
return err
}
defer out.Close()
// Write the body to file
_, err = io.Copy(out, resp.Body)
return err
}
带进度条的大文件下载
package main
import (
"fmt"
"io"
"net/http"
"os"
"strings"
"github.com/dustin/go-humanize"
)
type WriteCounter struct {
Total uint64
}
func (wc *WriteCounter) Write(p []byte) (int, error) {
n := len(p)
wc.Total += uint64(n)
wc.PrintProgress()
return n, nil
}
func (wc WriteCounter) PrintProgress() {
fmt.Printf("\r%s", strings.Repeat(" ", 35))
fmt.Printf("\rDownloading... %s complete", humanize.Bytes(wc.Total))
}
func main() {
fmt.Println("Download Started")
// 下载地址:
fileUrl := "http://xxxxxx.com/files/文件名称""
err := DownloadFile("保存文件名.png", fileUrl)
if err != nil {
panic(err)
}
fmt.Println("Download Finished")
}
func DownloadFile(filepath string, url string) error {
out, err := os.Create(filepath + ".tmp")
if err != nil {
return err
}
resp, err := http.Get(url)
if err != nil {
out.Close()
return err
}
defer resp.Body.Close()
counter := &WriteCounter{}
/*
io.TeeReader则可以传递计数器来跟踪进度
io.TeeReader返回一个将其从r读取的数据写入w的Reader接口。所有通过该接口对r的读取都会执行对应的对w的写入。没有内部的缓冲;
写入必须在读取完成前完成。写入时遇到的任何错误都会作为读取错误返回。
*/
if _, err = io.Copy(out, io.TeeReader(resp.Body, counter)); err != nil {
out.Close()
return err
}
fmt.Print("\n")
out.Close()
if err = os.Rename(filepath+".tmp", filepath); err != nil {
return err
}
return nil
}