Implementation of golang progress bar function


Recently, I’m working on a requirement. The function is very simple. It’s to develop a lightweight client to pass the content in a specified file through theTCPSend to the server. Because the file is very large, it may reach the order of 100g, so the processing will be relatively slow. In order to provide users with a more friendly display interface, the progress bar display function is added.

Here, I would like to talk about some ideas when I realize the function of the progress bar.

Achievement demonstration

Let’s take a look at the final product effect display:
Implementation of golang progress bar function

The progress bar consists of three parts, the first part is the main progress bar, the second part is the percentage, and the third part is a dynamic display of the current completed data and the total data.

Source code analysis

Because it is to print out the effect of the progress bar on the terminal, it is mainly to usefmt.PrintfIn function\rFormat controller. With this foundation, we can first design the structure as follows:

type Bar struct {
    Percentage Int64 // percentage
    Cur Int64 // current progress location
    Total Int64 // total progress
    Rate string // progress bar
    Graph string // display symbols

Among them, the percentage has nothing to say,curandtotalIs a group, which represents the current completed data and total data dynamically displayed in the third part.rateThe first part is the changing progress bar. It’s astringString of type.
The progress bar display tool also provides agraphWith it, users can customize the display pattern of the progress bar. For example, they can replace the blocks in the progress bar with#=@Wait for the pattern you can think of.


In order to call the progress bar tool conveniently, two initialization methods are provided for the structureNewOptionandNewOptionWithGraphThe second initialization method is to specify the display pattern.
NewOptionThe default display pattern is used, which is the box shown in the figure above. The implementation code is as follows:

func (bar *Bar) NewOption(start, total int64) {
    bar.cur = start = total
    if bar.graph == "" {
        bar.graph = "█"
    bar.percent = bar.getPercent()
    for i := 0; i < int(bar.percent); i += 2 {
        Bar. Rate + = bar. Graph // initialize the progress bar position

This function provides two parameters, which arestartandtotaltotalNeedless to say, it represents the total amount of tasks and provides astartParameter, indicating that it can be omitted from the0In the beginning, this means that if your program wants to support the breakpoint continuation function, the progress bar tool can still support it perfectly, just add thestartSet the value at the breakpoint. Of course, if you don’t need a breakpoint to continue, start every time0To begin with, you just need tostartSet the value to 0.
If you notice that I used thei += 2That’s what I’m going to say next. Because the percentage always comes from0reach100And the maximum length of my progress bar is 50 characters, which means that every time I grow2%The progress bar is going up one space, so the step size here is 2.
getPercentIt’s a basiscurandtotalA function to obtain the completion percentage of the current progress. Its implementation is relatively simple

func (bar *Bar) getPercent() int64 {
    return int64(float32(bar.cur) / float32( * 100)

The second initialization function is easier to implement, just put thegraphAfter re covering, call the initialization function above directly.

func (bar *Bar) NewOptionWithGraph(start, total int64, graph string) {
    bar.graph = graph
    bar.NewOption(start, total)

Progress bar display

So, how to realize the display function?
Generally, the call to display the progress bar is executed in the loop. Therefore, we only need to display the current progress status of each cycle in the loop.

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,

In this code, the most important is the last usefmt.PrintfThe printed sentence, through\rControl the printing effect.
Of course, in buildingrateIn the progress bar, I need to save the percentage of the last completion, only when the percentage has changed and the step size has changed2The length of the progress bar needs to be changed. If your screen is big enough, you can also make your progress bar as long as100In this way, you don’t need to control the step size of the progress bar to 2, every time it grows1%There is no problem if the progress bar advances one space.


Because the above printing does not print a new line character, it is necessary to print a new line character at the end of the progress (that is, when jumping out of the cycle). Therefore, a new line character is encapsulatedFinishFunction, which simply prints a line feed, indicating that the progress bar has been completed.

func (bar *Bar) Finish(){

How to call

To call the progress bar function, first of all, be sure to build oneBarObject. After initialization with this object, you can call the progress bar. A complete calling program is as follows:

func main(){
    var bar progressbar.Bar    
    bar.NewOption(0, 100)
    for i:= 0; i<=100; i++{

The above is the simplest call, and its running effect is as follows:
Implementation of golang progress bar function
Of course, you can also use another initialization function to specify the icon to be displayed, as follows:

bar.NewOptionWithGraph(0, 100, "#")

The display effect is as follows:
Implementation of golang progress bar function

Of course, in actual use, you are likely to only use sleep, but need to realize your own function function function, just need totime.Sleep(100*time.Millisecond)Replace it with your own code logic.