如何在控制台实现一个进度条
一、前言
在今天使用Java代码做一个集合的任务的时候,没在for循环中手动打印日志信息,导致在任务执行后根本不知道执行到了哪一步。
这点让我挺困扰的,于是在github上寻找有没有什么进度条的显示方式,我还真找到了。
看了一下代码,挺简单的,就将思路直接copy过来,实现了一个自己的控制台进度条。
vdurmont/etaprinter: Java console progress bar (github.com)
二、代码
抽象类ProcessBarUtil.java,里面有着基本的信息
| 12
 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
 
 | package com.banmoon.utils.processbar;
 import java.util.Iterator;
 import java.util.function.Consumer;
 
 
 
 
 
 public abstract class ProcessBarUtil<T> implements Iterable<T> {
 
 
 
 
 private final Iterable<T> data;
 
 
 
 
 private final Integer startNum;
 
 
 
 
 private Integer current;
 
 
 
 
 private final Integer endNum;
 
 
 
 
 private Integer processCurrentNum = 0;
 
 
 
 
 private final Integer processTotalNum = 100;
 
 public ProcessBarUtil(Iterable<T> data, Integer startNum, Integer current, Integer endNum) {
 this.data = data;
 this.startNum = startNum;
 this.current = current;
 this.endNum = endNum;
 }
 
 
 
 
 
 
 public void add(Integer num) {
 this.current += num;
 this.processCurrentNum = (int) (100.0 * current / endNum);
 updateProcessBar(processCurrentNum, processTotalNum);
 }
 
 
 
 
 
 
 public void update(Integer current) {
 this.current = current;
 this.processCurrentNum = (int) (100.0 * current / endNum);
 updateProcessBar(processCurrentNum, processTotalNum);
 }
 
 protected abstract void updateProcessBar(Integer processCurrentNum, Integer processTotalNum);
 
 @Override
 public Iterator<T> iterator() {
 return data.iterator();
 }
 
 @Override
 public void forEach(Consumer<? super T> action) {
 data.forEach(t -> {
 action.accept(t);
 add(1);
 });
 }
 }
 
 | 
以及它的第一个实现类ConsoleProcessBarUtil.java,使用控制台输出进度条
| 12
 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
 
 | package com.banmoon.utils.processbar;
 import cn.hutool.core.collection.IterUtil;
 
 import java.io.IOException;
 import java.io.OutputStream;
 import java.util.stream.IntStream;
 import java.util.stream.Stream;
 
 
 
 
 
 
 
 public class ConsoleProcessBarUtil<T> extends ProcessBarUtil<T> {
 
 private final OutputStream outputStream;
 
 
 
 
 private static final char incomplete = '░';
 
 
 
 
 private static final char complete = '█';
 
 
 private ConsoleProcessBarUtil(Iterable<T> data, Integer startNum, Integer current, Integer endNum) {
 super(data, startNum, current, endNum);
 outputStream = System.out;
 }
 
 public static <T> ProcessBarUtil<T> init(Iterable<T> data) {
 return new ConsoleProcessBarUtil<>(data, 0, 0, IterUtil.size(data));
 }
 
 public static ProcessBarUtil<?> init(Integer startNum, Integer endNum) {
 return new ConsoleProcessBarUtil<>(null, startNum, startNum, endNum);
 }
 
 @Override
 protected void updateProcessBar(Integer processCurrentNum, Integer processTotalNum) {
 String processBar = generateProcessBar(processCurrentNum, processTotalNum);
 try {
 outputStream.write("\r".getBytes());
 outputStream.write(processBar.getBytes());
 } catch (IOException e) {
 throw new RuntimeException("an error occurred while printing the progress bar");
 }
 }
 
 private String generateProcessBar(Integer processCurrentNum, Integer processTotalNum) {
 StringBuilder sb = new StringBuilder("[");
 Stream.generate(() -> complete)
 .limit(processCurrentNum)
 .forEach(sb::append);
 IntStream.range(processCurrentNum, processTotalNum)
 .mapToObj(i -> incomplete)
 .forEach(sb::append);
 sb.append("] ");
 if (processCurrentNum >= processTotalNum) {
 sb.append("complete\n");
 } else {
 sb.append(processCurrentNum).append("%");
 }
 return sb.toString();
 }
 
 }
 
 | 
三、测试效果
| 12
 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
 
 | package com.banmoon.utils.stream;
 import cn.hutool.core.util.RandomUtil;
 import com.banmoon.utils.processbar.ConsoleProcessBarUtil;
 import com.banmoon.utils.processbar.ProcessBarUtil;
 import org.junit.Assert;
 import org.junit.Test;
 
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
 
 public class ProcessBarUtilTest {
 
 @Test
 public void iterableTest() {
 List<Integer> list = IntStream.range(0, 100).boxed().collect(Collectors.toList());
 ConsoleProcessBarUtil
 .init(list)
 .forEach(str -> {
 try {
 
 TimeUnit.MILLISECONDS.sleep(RandomUtil.randomInt(50, 200));
 } catch (InterruptedException e) {
 throw new RuntimeException(e);
 }
 });
 Assert.assertEquals(list.size(), 100);
 }
 
 @Test
 public void forTest() {
 int current = 50;
 int total = 200;
 ProcessBarUtil<?> processBarUtil = ConsoleProcessBarUtil.init(current, total);
 while (current < total) {
 try {
 
 TimeUnit.MILLISECONDS.sleep(RandomUtil.randomInt(50, 200));
 } catch (InterruptedException e) {
 throw new RuntimeException(e);
 }
 current++;
 processBarUtil.update(current);
 }
 Assert.assertEquals(current, total);
 }
 
 
 }
 
 | 
运行后查看效果,成功

四、最后
后续会完善加上,执行的耗时,预计多少时间完成等信息。
以及看看除了控制台,还有没有其他实现。
我是半月,你我一同共勉!!!