Golang 使用http Client下载文件的实现方法

2020-01-28 14:00:56王振洲

这段代码堵塞住程序,然后定时器按照间隔时间来计算速度。这里可能会出现bug的地方就是在间隔时间内没有读取到数据的时候回直接跳出循环。现在这个时间点非常困,写个blog已经困的要死了以后有空把这个bug解决了吧


func bytesToSize(length int) string {
 var k = 1024 // or 1024
 var sizes = []string{"Bytes", "KB", "MB", "GB", "TB"}
 if length == 0 {
  return "0 Bytes"
 }
 i := math.Floor(math.Log(float64(length)) / math.Log(float64(k)))
 r := float64(length) / math.Pow(float64(k), i)
 return strconv.FormatFloat(r, 'f', 3, 64) + " " + sizes[int(i)]
}

这个函数是我从我个人的php项目中转换过来的


2018/08/17 00:24:50 [*] Filename go1.10.3.darwin-amd64.pkg
2018/08/17 00:24:51 [*] Speed 9.000 MB / 1s 
2018/08/17 00:24:52 [*] Speed 11.125 MB / 1s 
2018/08/17 00:24:53 [*] Speed 11.125 MB / 1s 
2018/08/17 00:24:54 [*] Speed 10.562 MB / 1s 
2018/08/17 00:24:55 [*] Speed 11.187 MB / 1s 
2018/08/17 00:24:56 [*] Speed 11.109 MB / 1s 
2018/08/17 00:24:57 [*] Speed 11.109 MB / 1s 
2018/08/17 00:24:58 [*] Speed 11.141 MB / 1s 
2018/08/17 00:24:59 [*] Speed 11.172 MB / 1s 
2018/08/17 00:25:00 [*] Speed 11.141 MB / 1s 
2018/08/17 00:25:01 [*] Speed 8.453 MB / 1s 
2018/08/17 00:25:02 [*] Speed 6.385 MB / 1s 
2018/08/17 00:25:03 [*] Speed 0 Bytes / 1s 

这是最终的运行结果,然后我再把全部的源码放在下面就去睡了。


package main

import (
 "net/http"
 "log"
 "time"
 "net/url"
 "path"
 "os"
 "io"
 "bufio"
 "math"
 "strconv"
)

var durl = "https://dl.google.com/go/go1.10.3.darwin-amd64.pkg";

func main() {
 uri, err := url.ParseRequestURI(durl)
 if err != nil {
  panic("网址错误")
 }

 filename := path.Base(uri.Path)
 log.Println("[*] Filename " + filename)

 client := http.DefaultClient;
 client.Timeout = time.Second * 60 //设置超时时间
 resp, err := client.Get(durl)
 if err != nil {
  panic(err)
 }
 if resp.ContentLength <= 0 {
  log.Println("[*] Destination server does not support breakpoint download.")
 }
 raw := resp.Body
 defer raw.Close()
 reader := bufio.NewReaderSize(raw, 1024*32);


 file, err := os.Create(filename)
 if err != nil {
  panic(err)
 }
 writer := bufio.NewWriter(file)

 buff := make([]byte, 32*1024)
 written := 0
 go func() {
  for {
   nr, er := reader.Read(buff)
   if nr > 0 {
    nw, ew := writer.Write(buff[0:nr])
    if nw > 0 {
     written += nw
    }
    if ew != nil {
     err = ew
     break
    }
    if nr != nw {
     err = io.ErrShortWrite
     break
    }
   }
   if er != nil {
    if er != io.EOF {
     err = er
    }
    break
   }
  }
  if err != nil {
   panic(err)
  }
 }()

 spaceTime := time.Second * 1
 ticker := time.NewTicker(spaceTime)
 lastWtn := 0
 stop := false

 for {
  select {
  case <-ticker.C:
   speed := written - lastWtn
   log.Printf("[*] Speed %s / %s n", bytesToSize(speed), spaceTime.String())
   if written-lastWtn == 0 {
    ticker.Stop()
    stop = true
    break
   }
   lastWtn = written
  }
  if stop {
   break
  }
 }
}

func bytesToSize(length int) string {
 var k = 1024 // or 1024
 var sizes = []string{"Bytes", "KB", "MB", "GB", "TB"}
 if length == 0 {
  return "0 Bytes"
 }
 i := math.Floor(math.Log(float64(length)) / math.Log(float64(k)))
 r := float64(length) / math.Pow(float64(k), i)
 return strconv.FormatFloat(r, 'f', 3, 64) + " " + sizes[int(i)]
}