Golang 使用http Client下载文件的实现方法
之前使用beego的http库的时候,有的情况需要下载文件。beego是能实现,但就是有点问题:不支持回调,没法显示下载速度,这在日常开发中是不可忍受的。
看了下beego的实现主要是使用了io.copy函数,于是就深入的看了下实现原理,发现挺简单的,于是就根据io.copy原理实现的一个简单的下载器
//定义要下载的文件 vardurl="https://dl.google.com/go/go1.10.3.darwin-amd64.pkg"; //解析url uri,err:=url.ParseRequestURI(durl) iferr!=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 deferraw.Close() reader:=bufio.NewReaderSize(raw,1024*32);
其实说实话不太清楚bufio能不能真正的加快htpp读取速度,没有做过跟不用bufio的对比。但是为了心理上的安心就加上去了
file,err:=os.Create(filename) iferr!=nil{ panic(err) } writer:=bufio.NewWriter(file)
同上也不太确定bufio能对文件写入增加多少速度
buff:=make([]byte,32*1024) written:=0 gofunc(){ for{ nr,er:=reader.Read(buff) ifnr>0{ nw,ew:=writer.Write(buff[0:nr]) ifnw>0{ written+=nw } ifew!=nil{ err=ew break } ifnr!=nw{ err=io.ErrShortWrite break } } ifer!=nil{ ifer!=io.EOF{ err=er } break } } iferr!=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()) ifwritten-lastWtn==0{ ticker.Stop() stop=true break } lastWtn=written } ifstop{ break } }
这段代码堵塞住程序,然后定时器按照间隔时间来计算速度。这里可能会出现bug的地方就是在间隔时间内没有读取到数据的时候回直接跳出循环。现在这个时间点非常困,写个blog已经困的要死了以后有空把这个bug解决了吧
funcbytesToSize(lengthint)string{ vark=1024//or1024 varsizes=[]string{"Bytes","KB","MB","GB","TB"} iflength==0{ return"0Bytes" } i:=math.Floor(math.Log(float64(length))/math.Log(float64(k))) r:=float64(length)/math.Pow(float64(k),i) returnstrconv.FormatFloat(r,'f',3,64)+""+sizes[int(i)] }
这个函数是我从我个人的php项目中转换过来的
2018/08/1700:24:50[*]Filenamego1.10.3.darwin-amd64.pkg 2018/08/1700:24:51[*]Speed9.000MB/1s 2018/08/1700:24:52[*]Speed11.125MB/1s 2018/08/1700:24:53[*]Speed11.125MB/1s 2018/08/1700:24:54[*]Speed10.562MB/1s 2018/08/1700:24:55[*]Speed11.187MB/1s 2018/08/1700:24:56[*]Speed11.109MB/1s 2018/08/1700:24:57[*]Speed11.109MB/1s 2018/08/1700:24:58[*]Speed11.141MB/1s 2018/08/1700:24:59[*]Speed11.172MB/1s 2018/08/1700:25:00[*]Speed11.141MB/1s 2018/08/1700:25:01[*]Speed8.453MB/1s 2018/08/1700:25:02[*]Speed6.385MB/1s 2018/08/1700:25:03[*]Speed0Bytes/1s
这是最终的运行结果,然后我再把全部的源码放在下面就去睡了。
packagemain import( "net/http" "log" "time" "net/url" "path" "os" "io" "bufio" "math" "strconv" ) vardurl="https://dl.google.com/go/go1.10.3.darwin-amd64.pkg"; funcmain(){ uri,err:=url.ParseRequestURI(durl) iferr!=nil{ panic("网址错误") } filename:=path.Base(uri.Path) log.Println("[*]Filename"+filename) client:=http.DefaultClient; client.Timeout=time.Second*60//设置超时时间 resp,err:=client.Get(durl) iferr!=nil{ panic(err) } ifresp.ContentLength<=0{ log.Println("[*]Destinationserverdoesnotsupportbreakpointdownload.") } raw:=resp.Body deferraw.Close() reader:=bufio.NewReaderSize(raw,1024*32); file,err:=os.Create(filename) iferr!=nil{ panic(err) } writer:=bufio.NewWriter(file) buff:=make([]byte,32*1024) written:=0 gofunc(){ for{ nr,er:=reader.Read(buff) ifnr>0{ nw,ew:=writer.Write(buff[0:nr]) ifnw>0{ written+=nw } ifew!=nil{ err=ew break } ifnr!=nw{ err=io.ErrShortWrite break } } ifer!=nil{ ifer!=io.EOF{ err=er } break } } iferr!=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()) ifwritten-lastWtn==0{ ticker.Stop() stop=true break } lastWtn=written } ifstop{ break } } } funcbytesToSize(lengthint)string{ vark=1024//or1024 varsizes=[]string{"Bytes","KB","MB","GB","TB"} iflength==0{ return"0Bytes" } i:=math.Floor(math.Log(float64(length))/math.Log(float64(k))) r:=float64(length)/math.Pow(float64(k),i) returnstrconv.FormatFloat(r,'f',3,64)+""+sizes[int(i)] }
以上这篇Golang使用httpClient下载文件的实现方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持毛票票。