pu369com

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("\r%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("\rDownloading... %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("\n")
    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

posted on 2020-05-21 18:03  pu369com  阅读(876)  评论(0编辑  收藏  举报

导航