张子阳的博客

首页 读书 技术 店铺 关于
张子阳的博客 首页 读书 技术 店铺 关于

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

感谢阅读,希望这篇文章能给你带来帮助!