由于有时候跑脚本几个小时看不到进度,所以想着写一个简单的命令行的进度条。类似下面这样的
其中的原理主要是\r回车符(将光标移动到行首)。这样的话就可以重新打印一行以覆盖之前的那一行。
func main() {
for i := 0; i < 10; i++ {
fmt.Printf("\r####")
}
}
// 结果:只会打印一行
// ####
首先来看进度条的结构。主要就是current:当前进度,和一共的任务数量total。
type Bar struct {
mu sync.Mutex
graph string // 显示符号
rate string // 进度条
percent int // 百分比
current int // 当前进度位置
total int // 总进度
start time.Time // 开始时间
}
初始化
func NewBar(current, total int) *Bar {
bar := new(Bar)
bar.current = current
bar.total = total
bar.start = time.Now()
if bar.graph == "" {
bar.graph = "█"
}
bar.percent = bar.getPercent()
for i := 0; i < bar.percent; i += 2 {
bar.rate += bar.graph //初始化进度条位置
}
return bar
}
func NewBarWithGraph(start, total int, graph string) *Bar {
bar := NewBar(start, total)
bar.graph = graph
return bar
}
计算当前百分比
根据当前的进度和总的进度来计算任务进行的百分比。
func (bar *Bar) getPercent() int {
return int((float64(bar.current) / float64(bar.total)) * 100)
}
获取当前花费时间
计算当前花费了多少时间 h表示小时,m表示分钟,s表示多少秒。
func (bar *Bar) getTime() (s string) {
u := time.Now().Sub(bar.start).Seconds()
h := int(u) / 3600
m := int(u) % 3600 / 60
if h > 0 {
s += strconv.Itoa(h) + "h "
}
if h > 0 || m > 0 {
s += strconv.Itoa(m) + "m "
}
s += strconv.Itoa(int(u)%60) + "s"
return
}
加载进度条
使用fmt.Printf 将光标设置到行首并打印进度条,以覆盖上一个进度条。
func (bar *Bar) load() {
last := bar.percent
bar.percent = bar.getPercent()
if bar.percent != last && bar.percent%2 == 0 {
bar.rate += bar.graph
}
fmt.Printf("\r[%-50s]% 3d%% %2s %d/%d", bar.rate, bar.percent, bar.getTime(), bar.current, bar.total)
}
设置进度
设置具体的完成任务数,或者任务数加或者减某个值。
func (bar *Bar) Reset(current int) {
bar.mu.Lock()
defer bar.mu.Unlock()
bar.current = current
bar.load()
}
func (bar *Bar) Add(i int) {
bar.mu.Lock()
defer bar.mu.Unlock()
bar.current += i
bar.load()
}
调用示例
func main() {
b := bar.NewBar(0,1000)
for i := 0 ;i < 1000; i++ {
b.Add(1)
time.Sleep(time.Millisecond*10)
}
}
至此以上就是全部的代码,非常简单,只是指在跑一些简单任务的时候能有一个提示。