golang 文件 下载 实现

示例如下:

下载文件过程中 生成XXX.download中间文件,下载完成后再重命名为待下载文件XXX

package mainimport (
    "crypto/md5"
    "errors"
    "fmt"
    "io"
    "io/IoUtil"
    "net/http"
    "os"
    "strconv"
    "time"
) 
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,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 //设置超时时间
    //get方法获取资源
    resp,err := client.Get(url)
    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
}

 

 

相关文章

功能概要:(目前已实现功能)公共展示部分:1.网站首页展示...
大体上把Python中的数据类型分为如下几类: Number(数字) ...
开发之前第一步,就是构造整个的项目结构。这就好比作一幅画...
源码编译方式安装Apache首先下载Apache源码压缩包,地址为ht...
前面说完了此项目的创建及数据模型设计的过程。如果未看过,...
python中常用的写爬虫的库有urllib2、requests,对于大多数比...