在我们日常开发中,会遇到一些耗时的操作,比如下载一个大文件,这时候如果能给用户一个进度提示,会显得比较友好,因为用户知道自己还要等多久可以,就可以下载好这个文件。

进度提示有很多种,比如百分比,但是它比较单调,如果更形象一些的话,可以使用进度条。

在偏向于UI或者GUI开发的时候,会有现成的进度条组件供我们使用,但是如果我们用Go语言开发CLI程序,如何在终端中显示进度条呢?

这就需要今天的主角儿 progressbar 出场了,这是比较经典的Go语言实现的进度条,schollz出品。https://github.com/schollz/progressbar

相比它的代码实现来说,它的使用非常简单,如下代码所示:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
package main

import (
  "time"

  "github.com/schollz/progressbar/v3"
)

func main() {
  bar := progressbar.Default(100)
  for i := 0; i < 100; i++ {
    bar.Add(1)
    time.Sleep(40 * time.Millisecond)
  }
}

只需要通过Default函数生成一个bar,然后通过它的Add方法增加进度即可。留意这里的100代表进度的最大值。

是不是感觉和我们常用的sync.WaitGroup很像?使用也非常简单。

了解了progressbar最基本的用法,现在我们来来战下,比如下载Golang Mac 安装包并显示进度,代码如下所示:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
func main() {
  golangPkg := "https://golang.google.cn/dl/go1.16.4.darwin-amd64.pkg"
  req, _ := http.NewRequest("GET", golangPkg, nil)
  resp, _ := http.DefaultClient.Do(req)
  defer resp.Body.Close()

  f, _ := os.OpenFile("go1.16.4.darwin-amd64.pkg", os.O_CREATE|os.O_WRONLY, 0644)
  defer f.Close()

  bar := progressbar.DefaultBytes(
    resp.ContentLength,
    "正在下载",
  )
  io.Copy(io.MultiWriter(f, bar), resp.Body)
}

以上代码的进度条使用到的就是基于字节大小计算的进度,用到了progressbar.DefaultBytes 函数。并且因为bar实现了io.Writer接口,所以可以被io.MultiWriter使用,这样在使用io.Copy下载文件的时候,就可以根据已经下载的字节、总的字节数,计算出进度。

运行以上代码,可以看到如下图所示的进度:

进度条

是不是非常完美,而且还挺漂亮。

在上面的示例中,我们是通过resp.ContentLength来获取文件的大小的,但是有时候,我们无法获取要下载文件的大小,这时候就可以使用-1代表,那么progressbar就会显示一个未知长度的进度条。

你自己可以把以上示例中的resp.ContentLength换成-1,自己运行看看效果。

以上是这个进度的示例以及效果,可能你觉得不太好看,没关系,progressbar支持自定义,你可以设置自己喜欢的主题、宽度、描述等,使用它的NewOptions函数即可,比较简单,这里就不再演示了。

Go社区现在也越来越成熟,贡献出的框架、库也会越来越多,如果你想实现某个功能,可以去Github找下,说不定有现成的库可以使用。

本文为原创文章,转载注明出处,欢迎扫码关注公众号flysnow_org或者网站asf http://www.flysnow.org/ ,第一时间看后续精彩文章。觉得好的话,请猛击文章右下角「好看」,感谢支持。

扫码关注