go分片下载文件代码片段

对于大文件,不推荐一次性读取,那样耗时久,还无法实时查看下载情况。

关键部分代码如下:

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
}

 

打赏
Bookmark the permalink.
0 0 投票数
文章评分
订阅评论
提醒
guest

0 评论
内联反馈
查看所有评论