如何在控制台实现一个进度条
一、前言
在今天使用Java
代码做一个集合的任务的时候,没在for
循环中手动打印日志信息,导致在任务执行后根本不知道执行到了哪一步。
这点让我挺困扰的,于是在github
上寻找有没有什么进度条的显示方式,我还真找到了。
看了一下代码,挺简单的,就将思路直接copy
过来,实现了一个自己的控制台进度条。
vdurmont/etaprinter: Java console progress bar (github.com)
二、代码
抽象类ProcessBarUtil.java
,里面有着基本的信息
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
| 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
,使用控制台输出进度条
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
| 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(); }
}
|
三、测试效果
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
| 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); }
}
|
运行后查看效果,成功
四、最后
后续会完善加上,执行的耗时,预计多少时间完成等信息。
以及看看除了控制台,还有没有其他实现。
我是半月,你我一同共勉!!!