今天小编就为大家分享一篇Golang 使用http Client下载文件的实现方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

之前使用beego的http库的时候,有的情况需要下载文件。beego是能实现,但就是有点问题:不支持回调,没法显示下载速度,这在日常开发中是不可忍受的。

看了下beego的实现主要是使用了io.copy函数,于是就深入的看了下实现原理,发现挺简单的,于是就根据io.copy原理实现的一个简单的下载器

//定义要下载的文件
var durl = "https://dl.google.com/go/go1.10.3.darwin-amd64.pkg";
//解析url
uri, err := url.ParseRequestURI(durl)
if err != nil {
 panic("网址错误")
}

正常的一个流程先看看Url有没有错误

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

使用path.Base取出url的文件名称,这里有个可能会出现bug的地方:如果这个网址是302跳转过去的话是没法取出跳转过后的文件名称。

取文件名称这步可以再发送http请求的时候 client.CheckRedirect定义一个函数取出文件名次即可。

client := http.DefaultClient;
client.Timeout = time.Second * 60 //设置超时时间
resp, err := client.Get(durl)

创建一个httpClient,另外这个客户端的Timeout是设置读取数据的时候多少时间算超时。

我这里比较推崇用Do方法传递一个Reqeust过去,应为有的url需要校验http头之类的,你问我为啥不用一个字懒。

raw := resp.Body
defer raw.Close()
reader := bufio.NewReaderSize(raw, 1024*32);

其实说实话不太清楚bufio能不能真正的加快htpp读取速度,没有做过跟不用bufio的对比。但是为了心理上的安心就加上去了

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

同上也不太确定bufio能对文件写入增加多少速度

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)
 }
}()

这个源码是我直接复制io.copyBuffer函数的只是做了一些简单的修改理解大概意思就行

//间隔时间
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
 }
}

这段代码堵塞住程序,然后定时器按照间隔时间来计算速度。这里可能会出现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)]
}

以上这篇Golang 使用http Client下载文件的实现方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持爱安网。

最新资讯
百度网盘:向湖北用户免费放送超级会员

百度网盘:向湖北用户免

百度网盘在其官方微博宣布,2月5日起推出“免费为湖北同
微软调整业务架构:Windows与硬件部门合并

微软调整业务架构:Wind

这对Panos Panay而言,既是机遇也是考验。
特斯拉未平仓空头仓位一天减少65万股

特斯拉未平仓空头仓位

相比前一日,特斯拉未平仓空头仓位减少65万股。空头仓位
58到家推“三保障三开通”政策?涉薪资、保险等方面

58到家推“三保障三开

针对疫情影响对服务业造成的影响,58到家推出“三保障三
欧盟正调查高通射频芯片 或将开出第三张罚单

欧盟正调查高通射频芯

据国外媒体报道,高通公司周三宣布,其出(bu)售(mai)给智能手机制造
京东7FRESH发布“人才共享”计划 缓解服务业压力

京东7FRESH发布“人才

2月5日,京东7FRESH发布了“人才共享”计划,邀请临时歇业
最新文章
GO常见的错误99%程序员会遇到(解决方法)

GO常见的错误99%程序

这篇文章主要介绍了GO常见的错误99%程序员会遇到,本文
用go写的五子棋预测算法的实现

用go写的五子棋预测算

这篇文章主要介绍了用go写的五子棋预测算法的实现,文中
Go使用defer函数要注意的几个点

Go使用defer函数要注

这篇文章主要介绍了Go使用defer函数要注意的几个点,文
自己动手用Golang实现约瑟夫环算法的示例

自己动手用Golang实现

这篇文章主要介绍了自己动手用Golang实现约瑟夫环算法
Go中如何使用set的方法示例

Go中如何使用set的方

这篇文章主要介绍了Go中如何使用set的方法示例,文中通
golang实现对docker容器心跳监控功能

golang实现对docker容

这篇文章主要介绍了golang实现对docker容器心跳监控功
江西快3 传奇私服_中国www.6byj.com 传奇私服考查询 www.181ok.com 传奇私服 传奇私服 传奇私服 传奇私服 zzqzsh.com gotomao.com 广东11选五开奖结果查
    <samp id="cwms4"><ruby id="cwms4"></ruby></samp><wbr id="cwms4"><noscript id="cwms4"></noscript></wbr>
    <kbd id="cwms4"><noscript id="cwms4"></noscript></kbd><bdo id="cwms4"><ruby id="cwms4"></ruby></bdo>

    <ins id="cwms4"></ins>
    <code id="cwms4"></code>
    <kbd id="cwms4"></kbd>
    <ins id="cwms4"></ins>
    <table id="cwms4"></table>
  1. <samp id="cwms4"><ruby id="cwms4"></ruby></samp>

    1. <em id="cwms4"><track id="cwms4"></track></em>
    2. <咸阳市>| <健康>| <西平县>| <博野县>| <从化市>| <威远县>| <汉源县>| <福鼎市>|