Go Tips: 控制台输出进度条
2018-12-22
张子阳
分类: Go 语言
有时候经常会有一些很小的需求,做一些工具应用,比如抓取网页、下载更新数据包等。对于耗时比较久的任务而言,最好是有一个进度显示,可以实时显示进度。下面的代码实现了这一功能,其主要的思想是通过“\r”符号,将光标挪至行首,然后进行输出,此时的输出就覆盖了之前的输出,从而实现实时动画的效果。
这个范例仅仅是一个demo,它还有严重的不足:它是单线程,并只刷新了一行的数据。而诸如下载或者抓取网页,通常都是多线程运行,那么就需要同时更新多行的进度条。此时,就不仅需要将光标挪至行首,还要挪到上一行或者前几行。这种操作的实现思想和这里是类似的,但是使用的特殊符号不同,不再是“\r”。具体可以参考这里:https://en.wikipedia.org/wiki/ANSI_escape_code。
除了控制光标位置以外,还可以控制输出的颜色。但大多数时候,因为时间紧张的关系,在控制台的输出上都非常简单,当需要复杂的输出,就直接写log日志了。
package main import ( "fmt" "math/rand" "strings" "time" ) func main() { testProgress() } // 测试进度条 func testProgress() { // 更新当前的状态 fmt.Println("Start processing... ") var total = 30 for i := 0; i < total; i++ { time.Sleep(time.Duration(rand.Intn(400)) * time.Millisecond) // 计算百分比 percent := int(float32(i+1) * 100.0 / float32(total)) pro := Progress(percent) pro.Show() } fmt.Printf("\nDone!\n") } // Progress 进度 type Progress int // Show 显示进度 func (x Progress) Show() { percent := int(x) // fmt.Println("percent: ", percent) total := 50 // 这个total是格子数 middle := int(percent * total / 100.0) // fmt.Printf("middle:%d\n", middle) arr := make([]string, total) for j := 0; j < total; j++ { if j < middle-1 { arr[j] = "-" } else if j == middle-1 { arr[j] = ">" } else { arr[j] = " " } } bar := fmt.Sprintf("[%s]", strings.Join(arr, "")) fmt.Printf("\r%s %%%d", bar, percent) }
输出如下,这里是动态的:
# go run main.go Start processing... [----------------------------------------> ] %83
感谢阅读,希望这篇文章能给你带来帮助!