• Go 语言显示下载文件进度/分段读取 io.TeeReader()


    想用go下载文件,代码:

    package main
    
    import (
        "fmt"
        "io"
        "net/http"
        "os"
        "strings"
    )
    
    // WriteCounter counts the number of bytes written to it. It implements to the io.Writer
    // interface and we can pass this into io.TeeReader() which will report progress on each
    // write cycle.
    type WriteCounter struct {
        Total uint64
    }
    
    func (wc *WriteCounter) Write(p []byte) (int, error) {
        n := len(p)
        wc.Total += uint64(n)
        wc.PrintProgress()
        return n, nil
    }
    
    func (wc WriteCounter) PrintProgress() {
        // Clear the line by using a character return to go back to the start and remove
        // the remaining characters by filling it with spaces
        fmt.Printf("
    %s", strings.Repeat(" ", 35))
    
        // Return again and print current status of download
        // We use the humanize package to print the bytes in a meaningful way (e.g. 10 MB)
        fmt.Printf("
    Downloading... %d B complete", wc.Total)
    }
    
    func main() {
        fmt.Println("Download Started")
    
        fileUrl := "https://dl.google.com/go/go1.11.1.src.tar.gz"
        err := DownloadFile("go1.11.1.src.tar.gz", fileUrl)
        if err != nil {
            panic(err)
        }
    
        fmt.Println("Download Finished")
    }
    
    // DownloadFile will download a url to a local file. It's efficient because it will
    // write as it downloads and not load the whole file into memory. We pass an io.TeeReader
    // into Copy() to report progress on the download.
    func DownloadFile(filepath string, url string) error {
    
        // Create the file, but give it a tmp file extension, this means we won't overwrite a
        // file until it's downloaded, but we'll remove the tmp extension once downloaded.
        out, err := os.Create(filepath + ".tmp")
        if err != nil {
            return err
        }
        defer out.Close()
    
        // Get the data
        resp, err := http.Get(url)
        if err != nil {
            return err
        }
        defer resp.Body.Close()
    
        // Create our progress reporter and pass it to be used alongside our writer
        counter := &WriteCounter{}
        _, err = io.Copy(out, io.TeeReader(resp.Body, counter))
        if err != nil {
            return err
        }
    
        // The progress use the same line so print a new line once it's finished downloading
        fmt.Print("
    ")
        out.Close()   //需增加这一句,否则在我的电脑上未成功改名。
        err = os.Rename(filepath+".tmp", filepath)
        if err != nil {
            return err
        }
    
        return nil
    }

    补充:原代码有bug,没能成功改名文件。需要在os.Rename()之前加上out.Close()才行(已补充到上述代码中)

    参考:https://blog.csdn.net/zhizhengguan/article/details/89066645

    https://www.twle.cn/t/385

  • 相关阅读:
    WAMP 2.2 配置与IIS共用单IP,多域名多网站配置方法
    [.NET MVC4 入门系列00]目录
    [.NET MVC4 入门系列04]Controller和View间交互原理
    [.NET MVC4 入门系列05]添加自定义查询页Search
    [.NET MVC4 入门系列02]MVC Movie 为项目添加Model
    [.NET MVC4 入门系列07] 在Model模型模块中添加验证
    [.NET MVC4 入门系列03]使用Controller访问Model中数据
    DateTime 类常用技巧
    Access 注意地方
    互联网公司老板的十大谎言,别对号入座
  • 原文地址:https://www.cnblogs.com/pu369/p/12932399.html
Copyright © 2020-2023  润新知