Java中的命令行进度栏


130

我有一个在命令行模式下运行的Java程序。我想显示一个进度条,显示完成的百分比。在Unix下使用wget会看到相同的进度条。这可能吗?


我不知道答案,你的具体问题,但你可以通过检查这个问题提到的库开始:stackoverflow.com/questions/435740/...
Jonik

谢谢。引用的库更多是关于命令行参数解析,而不是显示在控制台中。但是还是谢谢你。
g andrieu 2009年

7
这是主题。OP询问是否可能,不建议图书馆推荐(至少在当前编辑中如此)
Neil McGuigan

我尝试这段代码stackoverflow.com/questions/1001290/…并运行!(仅在终端中正确运行,而不在Eclipse中使用)
Wendel

Answers:


176

我以前已经实现了这种事情。它与Java无关,但与要发送到控制台的字符有关。

关键的区别是\n\r\n转到新行的开头。但是\r只是回车 -它可以回到同一行的开头。

所以要做的就是打印进度条,例如,通过打印字符串

"|========        |\r"

在进度条的下一个刻度上,用更长的条覆盖同一行。(因为我们使用\ r,所以我们保持在同一行)例如:

"|=========       |\r"

您要记住要做的是完成后,如果您只是打印

"done!\n"

您可能仍然会从该行的进度栏中看到一些垃圾。因此,在完成进度条之后,请确保打印足够的空格以将其从行中删除。如:

"done             |\n"

希望有帮助。


这真的是跨平台的吗?在Windows和Linux上,它可能工作正常,但是Macs呢?我没有一个,所以我不能尝试...
Radu Murzea

2
@RaduMurzea OS X是* NIX操作系统,因此,如果它在Linux上运行,它将在OS X上运行(并非对所有情况都适用,但在此处适用)。
bfontaine 2013年

3
谢谢!但是,这不适用于ant(在linux和osx上都尝试过;直接调用Java时可以正常工作)。有人知道吗?
user495285 2014年

请注意,这在内置控制台的eclipse中不起作用(至少对我而言)。但是,由于这是开发控制台,因此这无关紧要。
Qw3ry


46

https://github.com/ctongfei/progressbar,许可证:MIT

简单的控制台进度栏。现在,进度条编写在另一个线程上运行。

建议使用Menlo,Fira Mono,Source Pro或SF Mono,以获得最佳视觉效果。

对于Consolas或Andale Mono字体,请使用ProgressBarStyle.ASCII(请参见下文),因为框形绘图字形在这些字体中未正确对齐。

Maven:

<dependency>
  <groupId>me.tongfei</groupId>
  <artifactId>progressbar</artifactId>
  <version>0.5.5</version>
</dependency>

用法:

ProgressBar pb = new ProgressBar("Test", 100); // name, initial max
 // Use ProgressBar("Test", 100, ProgressBarStyle.ASCII) if you want ASCII output style
pb.start(); // the progress bar starts timing
// Or you could combine these two lines like this:
//   ProgressBar pb = new ProgressBar("Test", 100).start();
some loop {
  ...
  pb.step(); // step by 1
  pb.stepBy(n); // step by n
  ...
  pb.stepTo(n); // step directly to n
  ...
  pb.maxHint(n);
  // reset the max of this progress bar as n. This may be useful when the program
  // gets new information about the current progress.
  // Can set n to be less than zero: this means that this progress bar would become
  // indefinite: the max would be unknown.
  ...
  pb.setExtraMessage("Reading..."); // Set extra message to display at the end of the bar
}
pb.stop() // stops the progress bar

1
这看起来很整洁,它将允许我替换CLI上的几百个字符串缓冲区行。但是,如果我有一个应用程序在“滴答声”之间运行了几分钟(两次step()呼叫之间的间隔),该怎么办?您的库是否异步运行,从而允许时钟更新?如果我的图书馆运行了几天怎么办?是否使用该/r策略?这会导致数百兆的输出吗?
Groostav '18年

23

我发现以下代码可以正常工作。它将字节写入输出缓冲区。或许,使用像一个作家方法System.out.println()方法替换的发生\r,以\n匹配目标的本地行结束(如果没有正确配置)。

public class Main{
    public static void main(String[] arg) throws Exception {
        String anim= "|/-\\";
        for (int x =0 ; x < 100 ; x++) {
            String data = "\r" + anim.charAt(x % anim.length()) + " " + x;
            System.out.write(data.getBytes());
            Thread.sleep(100);
        }
    }
}

7

我已完成检查剩余下载文件的进度。

我会在文件下载中定期调用该方法,以检查文件总大小和剩余大小,并在中显示%

它也可以用于其他任务目的。

测试和输出示例

progressPercentage(0, 1000);
[----------] 0%

progressPercentage(10, 100);
[*---------] 10%

progressPercentage(500000, 1000000);
[*****-----] 50%

progressPercentage(90, 100);
[*********-] 90%

progressPercentage(1000, 1000);
[**********] 100%

用for循环测试

for (int i = 0; i <= 200; i = i + 20) {
    progressPercentage(i, 200);
    try {
        Thread.sleep(500);
    } catch (Exception e) {
    }
}

该方法可以轻松修改:

public static void progressPercentage(int remain, int total) {
    if (remain > total) {
        throw new IllegalArgumentException();
    }
    int maxBareSize = 10; // 10unit for 100%
    int remainProcent = ((100 * remain) / total) / maxBareSize;
    char defaultChar = '-';
    String icon = "*";
    String bare = new String(new char[maxBareSize]).replace('\0', defaultChar) + "]";
    StringBuilder bareDone = new StringBuilder();
    bareDone.append("[");
    for (int i = 0; i < remainProcent; i++) {
        bareDone.append(icon);
    }
    String bareRemain = bare.substring(remainProcent, bare.length());
    System.out.print("\r" + bareDone + bareRemain + " " + remainProcent * 10 + "%");
    if (remain == total) {
        System.out.print("\n");
    }
}

5

C#示例,但我假设这System.out.print在Java中是相同的。如果我错了,请随时纠正我。

基本上,您想\r在消息的开头写出转义字符,这将导致光标返回到行的开头(换行)而不移动到下一行。

    static string DisplayBar(int i)
    {
        StringBuilder sb = new StringBuilder();

        int x = i / 2;
        sb.Append("|");
        for (int k = 0; k < 50; k++)
            sb.AppendFormat("{0}", ((x <= k) ? " " : "="));
        sb.Append("|");

        return sb.ToString();
    }

    static void Main(string[] args)
    {
        for (int i = 0; i <= 100; i++)
        {
            System.Threading.Thread.Sleep(200);
            Console.Write("\r{0} {1}% Done", DisplayBar(i), i);
        }

        Console.ReadLine();

    }

很好的例子,肯定会有所帮助。谢谢。
g andrieu

美丽!谢谢。像吸引子一样工作。易于阅读。可爱
kholofelo Maloma

4

有点重构和更新了@maytham-ɯɐɥʇʎɐɯ的方法。现在它支持进度条的任意大小:

    public static void progressPercentage(int done, int total) {
        int size = 5;
        String iconLeftBoundary = "[";
        String iconDone = "=";
        String iconRemain = ".";
        String iconRightBoundary = "]";

        if (done > total) {
            throw new IllegalArgumentException();
        }
        int donePercents = (100 * done) / total;
        int doneLength = size * donePercents / 100;

        StringBuilder bar = new StringBuilder(iconLeftBoundary);
        for (int i = 0; i < size; i++) {
            if (i < doneLength) {
                bar.append(iconDone);
            } else {
                bar.append(iconRemain);
            }
        }
        bar.append(iconRightBoundary);

        System.out.print("\r" + bar + " " + donePercents + "%");

        if (done == total) {
            System.out.print("\n");
        }
    }

3

这是上述内容的修改版本:

private static boolean loading = true;
private static synchronized void loading(String msg) throws IOException, InterruptedException {
    System.out.println(msg);
    Thread th = new Thread() {
        @Override
        public void run() {
            try {
                System.out.write("\r|".getBytes());
                while(loading) {
                    System.out.write("-".getBytes());
                    Thread.sleep(500);
                }
                System.out.write("| Done \r\n".getBytes());
            } catch (IOException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    };
    th.start();
}

...主要

loading("Calculating ...");

2

使用Java Curses库可以实现这一点。就是我所发现的。我自己没有使用过它,也不知道它是否是跨平台的。


对于我需要的简单用法而言,诅咒可能会有些开销,但这肯定是正确的。谢谢。
g andrieu 2009年

2

当我需要延迟工具以防止出现竞争状况时,我使用“弹跳”进度条。

private void delay(long milliseconds) {
    String bar = "[--------------------]";
    String icon = "%";

    long startTime = new Date().getTime();
    boolean bouncePositive = true;
    int barPosition = 0;

    while((new Date().getTime() - startTime) < milliseconds) {
        if(barPosition < bar.length() && barPosition > 0) {
            String b1 = bar.substring(0, barPosition);
            String b2 = bar.substring(barPosition);
            System.out.print("\r Delaying: " + b1 + icon + b2);
            if(bouncePositive) barPosition++;
            else barPosition--;
        } if(barPosition == bar.length()) {
            barPosition--;
            bouncePositive = false;
        } if(barPosition == 0) {
            barPosition++;
            bouncePositive = true;
        }

        try { Thread.sleep(100); }
        catch (Exception e) {}
    }
    System.out.print("\n");
}

2

我最近遇到了同样的问题,您可以检查我的代码:我将其设置为5%的#号,您可以稍后对其进行修改。

public static void main (String[] args) throws java.lang.Exception
{
    int i = 0;
    while(i < 21) {
        System.out.print("[");
        for (int j=0;j<i;j++) {
            System.out.print("#");
        }

        for (int j=0;j<20-i;j++) {
            System.out.print(" ");
        }

        System.out.print("] "+  i*5 + "%");
        if(i<20) {
            System.out.print("\r");
            Thread.sleep(300);
        }
        i++;
    }
    System.out.println();
}

1
public static void main(String[] argv) throws Exception{


    System.out.write("\r".getBytes());
    int percentage =10;
    while(percentage <= 100) {
        String temp =generateStars(percentage);
        System.out.write(temp.getBytes());
        System.out.print("\b\b\b");
        percentage = percentage+10;
        Thread.sleep(500);
    }
}

    public static String generateStars(int percentage)
    {
        int startsNum = percentage / 4;
        StringBuilder builder = new StringBuilder();
        while(startsNum >= 0)
        {
        builder.append("*");
        startsNum--;
        }
        builder.append(percentage+"%");
        return builder.toString();
    }

1

我将Eoin Campbell的代码编辑为Java,并以百分比形式添加了格式化进度。

public static String progressBar(int currentValue, int maxValue) {
    int progressBarLength = 33; //
    if (progressBarLength < 9 || progressBarLength % 2 == 0) {
        throw new ArithmeticException("formattedPercent.length() = 9! + even number of chars (one for each side)");
    }
    int currentProgressBarIndex = (int) Math.ceil(((double) progressBarLength / maxValue) * currentValue);
    String formattedPercent = String.format(" %5.1f %% ", (100 * currentProgressBarIndex) / (double) progressBarLength);
    int percentStartIndex = ((progressBarLength - formattedPercent.length()) / 2);

    StringBuilder sb = new StringBuilder();
    sb.append("[");
    for (int progressBarIndex = 0; progressBarIndex < progressBarLength; progressBarIndex++) {
        if (progressBarIndex <= percentStartIndex - 1
        ||  progressBarIndex >= percentStartIndex + formattedPercent.length()) {
            sb.append(currentProgressBarIndex <= progressBarIndex ? " " : "=");
        } else if (progressBarIndex == percentStartIndex) {
            sb.append(formattedPercent);
        }
    }
    sb.append("]");
    return sb.toString();
}

int max = 22;
System.out.println("Generating report...");
for (int i = 0; i <= max; i++) {
   Thread.sleep(100);
   System.out.print(String.format("\r%s", progressBar(i, max)));
}
System.out.println("\nSuccessfully saved 32128 bytes");

并输出:

Generating report...

[========      24.2 %             ]

[============  45.5 %             ]

[============  78.8 % =====       ]

[============  87.9 % ========    ]

[============ 100.0 % ============]

Successfully saved 32128 bytes

0
public class ProgressBar
{
    private int max;

    public ProgressBar(int max0) {
        max = max0;
        update(0);
    }

    public void update(int perc) {
        String toPrint = "|";
        for(int i = 0; i < max; i++) {
            if(i <= (perc + 1))
                toPrint += "=";
            else
                toPrint += " ";
        }

        if(perc >= max)
            Console.print("\r");
        else
            Console.print(toPrint + "|\r");
    }
}

0
public class Main {

    public static void main(String[] args) throws Exception {

        System.out.println("Loading : ");
            int count =1;
            for(int j=1;j<150;j++){

                System.out.print("\r");
                if(count==1){
                    System.out.print("/");
                    count++;
                }
                else if(count==2){
                    System.out.print("|");
                    count++;
                }
                else if(count==3){
                    System.out.print("-");
                    count++;
                }
                else if(count==4){
                    System.out.print("\\");
                    count++;
                }
                else if(count==5){
                    System.out.print("|");
                    count++;
                }
                else
                    count = 1;
            Thread.sleep(200);
        }

        }

    }

0
static String progressBar(int progressBarSize, long currentPosition, long startPositoin, long finishPosition) {
    String bar = "";
    int nPositions = progressBarSize;
    char pb = '░';
    char stat = '█';
    for (int p = 0; p < nPositions; p++) {
        bar += pb;
    }
    int ststus = (int) (100 * (currentPosition - startPositoin) / (finishPosition - startPositoin));
    int move = (nPositions * ststus) / 100;
    return "[" + bar.substring(0, move).replace(pb, stat) + ststus + "%" + bar.substring(move, bar.length()) + "]";
}

在此处输入图片说明

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.