【问题标题】:golang dynamic progressbargolang动态进度条
【发布时间】:2015-05-29 15:00:33
【问题描述】:

我正在尝试使用 golang 下载文件。

我正在下载文件,没关系。在我使用 cheggaaa 的进度条库之后。但我不能动态。

如何做动态进度条?

我的代码如下:

主包

import (
    "flag"
    "fmt"
    "io"
    "net/http"
    "net/url"
    "os"
    "strings"
    "github.com/cheggaaa/pb"
    "time"
)

/*
    usage = usage text
    version = current number
    help use Sprintf
    *cliUrl from cmd
    *cliVersion from cmd
    *cliHelp * from cmd
*/
var (
    usage      = "Usage: ./gofret -url=http://some/do.zip"
    version    = "Version: 0.1"
    help       = fmt.Sprintf("\n\n  %s\n\n\n  %s", usage, version)
    cliUrl     *string
    cliVersion *bool
    cliHelp    *bool
)

func init() {
    /*
        if *cliUrl != "" {
            fmt.Println(*cliUrl)
        }

        ./gofret -url=http://somesite.com/somefile.zip
        ./gofret -url=https://github.com/aligoren/syspy/archive/master.zip
    */
    cliUrl = flag.String("url", "", usage)

    /*
        else if *cliVersion{
            fmt.Println(flag.Lookup("version").Usage)
        }

        ./gofret -version
    */
    cliVersion = flag.Bool("version", false, version)

    /*
        if *cliHelp {
            fmt.Println(flag.Lookup("help").Usage)
        }

        ./gofret -help
    */
    cliHelp = flag.Bool("help", false, help)
}

func main() {

    /*
        Parse all flags
    */
    flag.Parse()

    if *cliUrl != "" {
        fmt.Println("Downloading file")

        /* parse url from *cliUrl */
        fileUrl, err := url.Parse(*cliUrl)

        if err != nil {
            panic(err)
        }

        /* get path from *cliUrl */
        filePath := fileUrl.Path

        /*
            seperate file.
            http://+site.com/+(file.zip)
        */
        segments := strings.Split(filePath, "/")

        /*
            file.zip filename lenth -1
        */
        fileName := segments[len(segments)-1]

        /*
            Create new file.
            Filename from fileName variable
        */
        file, err := os.Create(fileName)

        if err != nil {
            fmt.Println(err)
            panic(err)
        }
        defer file.Close()

        /*
            check status and CheckRedirect
        */
        checkStatus := http.Client{
            CheckRedirect: func(r *http.Request, via []*http.Request) error {
                r.URL.Opaque = r.URL.Path
                return nil
            },
        }

        /*
            Get Response: 200 OK?
        */
        response, err := checkStatus.Get(*cliUrl)

        if err != nil {
            fmt.Println(err)
            panic(err)
        }
        defer response.Body.Close()
        fmt.Println(response.Status) // Example: 200 OK

        /*
            fileSize example: 12572 bytes
        */
        fileSize, err := io.Copy(file, response.Body)
        /*
            progressbar worked after download :(
        */
        var countSize int = int(fileSize/1000)
        count := countSize
        bar := pb.StartNew(count)
        for i := 0; i < count; i++ {
            bar.Increment()
            time.Sleep(time.Millisecond)
        }
        bar.FinishPrint("The End!")

        if err != nil {
            panic(err)
        }


        fmt.Printf("%s with %v bytes downloaded", fileName, count)

    } else if *cliVersion {
        /*
            lookup version flag's usage text
        */
        fmt.Println(flag.Lookup("version").Usage)
    } else if *cliHelp {
        /*
            lookup help flag's usage text
        */
        fmt.Println(flag.Lookup("help").Usage)
    } else {
        /*
            using help's usage text for handling other status
        */
        fmt.Println(flag.Lookup("help").Usage)
    }
}

当我的程序运行时:

Downloading file
200 OK

下载后工作进度条:

6612 / 6612 [=====================================================] 100.00 % 7s
The End!
master.zip with 6612 bytes downloaded

我的进度条代码如下:

/*
    progressbar worked after download :(
*/
var countSize int = int(fileSize/1000)
count := countSize
bar := pb.StartNew(count)
for i := 0; i < count; i++ {
    bar.Increment()
    time.Sleep(time.Millisecond)
}
bar.FinishPrint("The End!")

如何解决进度条问题?

【问题讨论】:

  • 您在启动进度条之前就已经下载了文件。
  • @JimB 我试过但没有工作,因为我得到 fileSize undefined 错误

标签: go progress-bar


【解决方案1】:

不需要更多的 goroutine。刚读吧

// start new bar
bar := pb.New(fileSize).SetUnits(pb.U_BYTES)
bar.Start()
// create proxy reader
rd := bar.NewProxyReader(response.Body)
// and copy from reader
io.Copy(file, rd)

【讨论】:

    【解决方案2】:

    我写了下面的东西,它在一般情况下是正确的,与进度条无关,但是这个库正是设计来处理这个问题的,对它有专门的支持,并给出了@987654321 @。


    您需要在更新进度条的同时运行下载,目前您正在下载整个文件,然后更新进度条。

    这有点草率,但应该能让你朝着正确的方向前进:

    首先,获取预期的文件大小:

        filesize := response.ContentLength
    

    然后在 goroutine 中开始下载:

        go func() {
            n, err := io.Copy(file, response.Body)
            if n != filesize {
                log.Fatal("Truncated")
            }
            if err != nil {
                log.Fatalf("Error: %v", err)
            }
        }()
    

    然后更新你的进度条:

        countSize := int(filesize / 1000)
        bar := pb.StartNew(countSize)
        var fi os.FileInfo
        for fi == nil || fi.Size() < filesize {
            fi, _ = file.Stat()
            bar.Set(int(fi.Size() / 1000))
            time.Sleep(time.Millisecond)
        }
        bar.FinishPrint("The End!")
    

    就像我说的,这有点草率;您可能希望根据文件的大小更好地缩放条形图,而 log.Fatal 调用很难看。但它处理了问题的核心。

    或者,您可以通过编写自己的io.Copy 版本来完成此操作而无需goroutine。从response.Body 读取一个块,更新进度条,然后将一个块写入file。这可以说更好,因为您可以避免睡眠呼叫。

    【讨论】:

    【解决方案3】:

    其实你可以通过下面这段代码自己实现进度条。

    func (bar *Bar) Play(cur int64) {
     bar.cur = cur
     last := bar.percent
     bar.percent = bar.getPercent()
     if bar.percent != last && bar.percent%2 == 0 {
       bar.rate += bar.graph
     }
     fmt.Printf("\r[%-50s]%3d%% %8d/%d", bar.rate, bar.percent, bar.cur, bar.total)
    }
    

    这里的关键是使用转义\r,它将用更新的进度替换当前进度,从而产生动态效果。

    详细解释可以在here找到。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-15
      相关资源
      最近更新 更多