前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何在控制台实现一个进度条

如何在控制台实现一个进度条

作者头像
半月无霜
发布2024-03-09 09:04:18
1190
发布2024-03-09 09:04:18
举报
文章被收录于专栏:半月无霜半月无霜

如何在控制台实现一个进度条

一、前言

在今天使用Java代码做一个集合的任务的时候,没在for循环中手动打印日志信息,导致在任务执行后根本不知道执行到了哪一步。

这点让我挺困扰的,于是在github上寻找有没有什么进度条的显示方式,我还真找到了。

看了一下代码,挺简单的,就将思路直接copy过来,实现了一个自己的控制台进度条。

vdurmont/etaprinter: Java console progress bar (github.com)

二、代码

抽象类ProcessBarUtil.java,里面有着基本的信息

代码语言:javascript
复制
package com.banmoon.utils.processbar;

import java.util.Iterator;
import java.util.function.Consumer;

/**
 * @author banmoon
 * @date 2024/03/08 15:52:13
 */
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;
    }

    /**
     * 添加进度
     *
     * @param num 本次进度数量
     */
    public void add(Integer num) {
        this.current += num;
        this.processCurrentNum = (int) (100.0 * current / endNum);
        updateProcessBar(processCurrentNum, processTotalNum);
    }

    /**
     * 更新进度条
     *
     * @param current 当前进度
     */
    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,使用控制台输出进度条

代码语言:javascript
复制
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;

/**
 * 控制台打印输出进度条
 *
 * @author banmoon
 * @date 2024/03/08 16:05:26
 */
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();
    }

}

三、测试效果

代码语言:javascript
复制
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);
    }


}

运行后查看效果,成功

abc
abc

四、最后

后续会完善加上,执行的耗时,预计多少时间完成等信息。

以及看看除了控制台,还有没有其他实现。

我是半月,你我一同共勉!!!

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-03-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 如何在控制台实现一个进度条
    • 一、前言
      • 二、代码
        • 三、测试效果
          • 四、最后
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档