对于大文件,不推荐一次性读取,那样耗时久,还无法实时查看下载情况。
关键部分代码如下:
1、会生成一个 下载文件名.download的临时文件,下载完后进行重命名。
2、文件下载情况,在downloadFile的 fb 回调函数中获取,go donloanFile(xx,xxx,cookie,fb)
func IsFileExist(filename string, filesize int64) bool { info, err := os.Stat(filename) if os.IsNotExist(err) { fmt.Println(info) return false } if filesize == info.Size() { fmt.Println("安装包已存在!", info.Name(), info.Size(), info.ModTime()) return true } del := os.Remove(filename) if del != nil { fmt.Println(del) } return false } func downloadFile(url string, localPath string,cookies string, fb func(length, downLen int64)) error { var ( fsize int64 buf = make([]byte, 32*1024) written int64 ) tmpFilePath := localPath + ".download" fmt.Println(tmpFilePath) //创建一个http client //client := new(http.Client) //client.Timeout = time.Second * 60 //设置超时时间 client := &http.Client{} //提交请求 reqest, err := http.NewRequest("GET", url, nil) //增加header选项 reqest.Header.Add("Cookie", cookies) reqest.Header.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36") //reqest.Header.Add("X-Requested-With", "xxxx") //get方法获取资源 //resp, err := client.Get(url) resp, err := client.Do(reqest) if err != nil { return err } //读取服务器返回的文件大小 fsize, err = strconv.ParseInt(resp.Header.Get("Content-Length"), 10, 32) if err != nil { fmt.Println(err) } if IsFileExist(localPath, fsize) { return err } fmt.Println("fsize", fsize) //创建文件 file, err := os.Create(tmpFilePath) if err != nil { return err } defer file.Close() if resp.Body == nil { return errors.New("body is null") } defer resp.Body.Close() //下面是 io.copyBuffer() 的简化版本 for { //读取bytes nr, er := resp.Body.Read(buf) if nr > 0 { //写入bytes nw, ew := file.Write(buf[0:nr]) //数据长度大于0 if nw > 0 { written += int64(nw) } //写入出错 if ew != nil { err = ew break } //读取是数据长度不等于写入的数据长度 if nr != nw { err = io.ErrShortWrite break } } if er != nil { if er != io.EOF { err = er } break } //没有错误了快使用 callback fb(fsize, written) } fmt.Println(err) if err == nil { file.Close() err = os.Rename(tmpFilePath, localPath) fmt.Println(err) } return err }