引言

素材参考:程序员Cafe

今天刷到一个视频看到了一个有趣的效果,定义一个for循环遍历,在控制台输出一个进度条显示遍历的进度。
代码很简单就是下面几行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class ProgressBarDemo {
public static void main(String[] args) {

int size = 500;
System.out.println("开始运行");

for (int i = 0; i <= size; i++) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.print("进度:"+ i + "/" + size + "\r");
}

System.out.println("\n"+"运行结束");
}
}

效果如下:
demo01

\r\n

\r\n起源于老式打印机,\r表示当打印机打字时,每打一个字,中间的字车就会像左移动一位,当按下回车键时字车就会回到行首;\n表示按下换行键时,纸张滚筒就会向下滚动一行。所以\r\n的作用就是将光标移动至下一行的行首

  • \r:作用是将光标回到行首。
  • \n:作用是将光标往下移动一行。

所以前面的演示代码就可以这样解释:输出进度条的时候,每次输出完进度条,都会将光标移动到行首输出,这样,就会覆盖掉之前的进度条,从而实现进度条的动态更新。

更多进度条样式

  1. 进度条工具类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    package com.xnj;

    import lombok.Getter;

    /**
    * 进度条演示类
    */
    public class ProgressBar {
    private final int total;
    private final int width;//宽度
    private int current;//当前
    private Style style;//样式

    private final static Style STYLE_1 = new Style("#", " ", "");
    private final static Style STYLE_2 = new Style("#", "=", "");
    private final static Style STYLE_3 = new Style("=", " ", ">");

    public ProgressBar(int total, int width, int style) {
    this.total = total;
    this.width = width;
    this.current = 0;
    if (style == 1) {
    this.style = STYLE_1;
    } else if (style == 2) {
    this.style = STYLE_2;
    } else {
    this.style = STYLE_3;
    }
    }

    public void start() {
    System.out.println("\n开始执行任务...");
    }

    public void finish() {
    System.out.println("\n任务执行结束...");
    }

    // 传入当前进度
    public void update(int progress) {
    this.current = progress;
    print();
    }

    /**
    * 打印当前进度的函数
    * 该函数通过计算当前进度与总进度的比例来确定进度条的显示状态
    * 使用字符串构建进度条,并在控制台中动态显示
    * 当进度达到100%时,调用finish函数表示结束
    */
    private void print() {
    //计算进度百分比
    double percentage = (double) current / total;
    //根据进度百分比和进度条宽度计算进度标记数
    int progressMarks = (int) (percentage * width);

    //创建字符串构建器来构建进度条字符串
    StringBuilder bar = new StringBuilder();
    //添加进度百分比和进度条起始部分
    bar.append(String.format("当前进度: %3d%% [", (int) (percentage * 100)));
    //标记是否是右侧进度条的开始
    boolean firstRight = true;
    //遍历进度条宽度,根据进度标记数添加相应的进度条字符
    for (int i = 0; i < width; i++) {
    if (i < progressMarks) {
    //进度未完成部分
    bar.append(style.leftStr);
    } else {
    //进度完成部分
    if (firstRight) {
    //右侧进度条开始字符
    bar.append(style.leftEndStr);
    firstRight = false;
    }
    //右侧进度条字符
    bar.append(style.rightStr);
    }
    }
    //添加进度条结束部分
    bar.append("]");

    //动态更新控制台输出
    System.out.print("\r" + bar);
    //进度完成时,调用finish函数
    if (percentage >= 1) {
    finish();
    }
    }



    @Getter
    private static class Style {
    private String leftStr; //进度条的左部字符
    private String rightStr; //进度条的右部字符
    private String leftEndStr; //进度条的左部结束字符

    public Style(String leftStr, String rightStr, String leftEndStr) {
    this.leftStr = leftStr;
    this.rightStr = rightStr;
    this.leftEndStr = leftEndStr;
    }
    }

    }
  2. 测试类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    public class LoopProgressDemo {
    public static void main(String[] args) {
    int size = 500;
    // 创建进度条对象,(进度,宽度,样式)
    ProgressBar progressBar = new ProgressBar(size, 60, 3);

    System.out.println("开始运行");
    for (int i = 0; i < size; i++) {
    doSth();
    progressBar.update(i + 1);
    }
    }

    // 模拟耗时操作
    private static void doSth() {
    try {
    Thread.sleep(10);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    }
  3. 运行结果
    样式1:
    loopdemo01
    样式2:
    loopdemo02
    样式3:
    loopdemo03