DEV

Go - ダウンロードとProgress bar表示

#Go

参考:Code-Hex/pget

rangeというのをheaderにセットすると、途中から途中までをダウンロードできるのか。これで分割ダウンロードとかリジュームとかできるらしい。pgetみながら自分でも一応簡単なダウンロード+Progress barをつくってみた。

main.go

package main
import (
"fmt"
"net/http"
"log"
"os"
"io"
)
var target_url = "https://www.imagemagick.org/download/linux/CentOS/x86_64/ImageMagick-7.0.6-0.x86_64.rpm"
var out_dir = "."
type Target struct {
url string
dir_path string
file_name string
file_size int64
}
func main() {
fmt.Println("test file download")
target := Target{
url: target_url,
dir_path: out_dir,
}
check(&target)
download(&target)
}
func check(t *Target) {
fmt.Println("checking url...")
res, err := http.Head(t.url)
chkErr(err)
if res.Header.Get("Accept-Ranges") != "bytes" {
log.Fatal("not supported range access.")
}
if res.ContentLength <= 0 {
log.Fatal("invalid content length.")
}
t.file_size = int64(res.ContentLength)
t.file_name = GetFileName(t.url)
fmt.Println("check ok.")
}
func download(t *Target){
fmt.Println("downloading...")
req, err := http.NewRequest("GET", t.url, nil)
chkErr(err)
req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", 0, t.file_size))
res, err := http.DefaultClient.Do(req)
chkErr(err)
defer res.Body.Close()
out_path := GetFilePath(t.dir_path, t.file_name)
out, err := os.Create(out_path)
chkErr(err)
defer out.Close()
ch := make(chan int)
go ProgressBar(t, &amp;out_path, ch)
io.Copy(out, res.Body)
<- ch
}
func chkErr(err error){
if err != nil {
log.Fatal(err)
}
}

util.go

package main
import (
"gopkg.in/cheggaaa/pb.v2"
"time"
"net/url"
"path/filepath"
"os"
)
func GetFileName(u string) string {
result, err := url.Parse(u)
chkErr(err)
return filepath.Base(result.Path)
}
func GetFilePath(d, f string) string {
return filepath.Join(d, f)
}
func ProgressBar(t *Target, file_path *string, ch chan int){
file_size := t.file_size
now_size := int64(0)
bar := pb.Start64(file_size)
for {
fi, err := os.Stat(*file_path)
chkErr(err)
now_size = fi.Size()
if now_size < file_size {
bar.SetCurrent(now_size)
} else {
bar.SetCurrent(file_size)
bar.Finish()
ch <- 1
break
}
time.Sleep(100 * time.Millisecond)
}
}