package breakpointContinuation
import (
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"strconv"
"strings"
"testing"
)
const (
// 断点续传下载正常响应码
NormalRespCode = "206 Partial Content"
// 断点续传下载,偏移量值超文件最大值长度错误响应码
ErrRespCode = "416 Requested Range Not Satisfiable"
// 七牛文件
SrcFileUrl = "http://qnota.xxxxxx"
// (文件下载的进度)已下载长度记录文本地址
FileName = "ac_ota"
TempFile = "F:\\pic\\" + FileName + "_temp.txt"
// 下载到本地的文件地址
DestFile ="F:\\pic\\" + FileName + "_bak"
BuffByte = 1024 * 20 -1
)
func TestDown(t *testing.T) {
//file2,_:=os.OpenFile(destFile,os.O_CREATE|os.O_WRONLY,os.ModePerm)
file2, err := os.Create(DestFile)
defer file2.Close()
if err != nil {
panic(err)
}
file3,_:=os.OpenFile(TempFile,os.O_CREATE|os.O_RDWR,os.ModePerm)
//1.读取临时文件中的数据,根据seek
file3.Seek(0,io.SeekStart)
bs:=make([]byte,100,100)
n1,err:=file3.Read(bs)
countStr:=string(bs[:n1])
countArr := strings.Split(countStr, "/")
var count, total int64 = 0, 0
var bfb = "0%"
var countf, totalf float64
countf, totalf = 0.0001, 10000
if len(countArr) >= 3 {
count,_=strconv.ParseInt(countArr[0],10,64)
total,_=strconv.ParseInt(countArr[1],10,64)
bfb = countArr[2]
//countf,_=strconv.ParseFloat(countArr[0], 64)
//totalf,_=strconv.ParseFloat(countArr[1], 64)
}
//bfb := fmt.Sprintf("%.2f", countf/totalf*100)+"%"
fmt.Println(fmt.Sprintf("开始下载,已下载:%d, 总共:%d, 进度:%s", count, total, bfb))
for {
req, err := http.NewRequest(http.MethodGet, SrcFileUrl, nil)
if err != nil {
return
}
// Range实现: fmt.Sprintf("bytes=%d-%d", h.StartPos, h.EndPos)
range01 := fmt.Sprintf("bytes=%d-%d", count , count + BuffByte)
req.Header.Set("Range", range01)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Println("request fail:", err)
return
}
defer resp.Body.Close()
//fmt.Println("Accept-Ranges:", resp.Header.Get("Accept-Ranges"))
Content_Range := resp.Header.Get("Content-Range")
totalRange := strings.Split(Content_Range, "/")
if len(totalRange) >= 2 {
total,_ =strconv.ParseInt(totalRange[1], 10,64)
}
//fmt.Println("Content-Length:", resp.Header.Get("Content-Length"), "返回总Length:", total)
// 206 Partial Content\416 Requested Range Not Satisfiable
fmt.Println("resp.Status:", resp.Status, resp.Status == "206 Partial Content" )
if resp.Status != NormalRespCode {
if resp.Status == ErrRespCode {
fmt.Println("文件下载完毕。。")
file3.Close()
} else {
fmt.Println(fmt.Sprintf("文件传输异常报错:err[%s]", resp.Status))
}
break
}
n3:=-1//写入的数据量
file2.Seek(count,0) // 设置file2下一次读或者写的起点
data, err := ioutil.ReadAll(resp.Body)
//fmt.Println("data size:", len(data))
//io.Copy(file2, res.Body)
n3,_=file2.Write(data)
count += int64(n3)
countf = float64(count)
totalf = float64(total)
bfb = fmt.Sprintf("%.2f", countf/totalf*100)+"%"
fmt.Println("本次读取了:", n3, "总共已下载:", count, "文件总大小:", total, "下载进度:", bfb)
w := strconv.Itoa(int(count)) + "/" + strconv.Itoa(int(total)) + "/" + bfb
file3.Seek(0,io.SeekStart) // 设置file3的下次读写起点为源点:0点,即覆盖重写。
file3.WriteString(w)
// 假装断电
if count> 1024*1024*4{
panic("假装断电了。。。,假装的。。。")
}
}
}
?异常打印:
?
正常打印:?
?
最后看记录文本:
?
?
|