Индикатор выполнения командной строки в Java - PullRequest
118 голосов
/ 12 мая 2009

У меня есть программа на Java, работающая в режиме командной строки. Я хотел бы отобразить индикатор выполнения, показывающий процент выполненной работы. Такой же индикатор выполнения вы увидите при использовании wget под unix. Возможно ли это?

Ответы [ 13 ]

160 голосов
/ 12 мая 2009

Я реализовывал подобные вещи раньше. Дело не столько в java, сколько в том, какие символы отправлять на консоль.

Ключ - разница между \n и \r. \n идет к началу новой строки. Но \r это просто возврат каретки - он возвращается к началу той же строки.

Итак, вам нужно распечатать индикатор выполнения, например, напечатав строку

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

На следующем тике индикатора выполнения перезаписать эту же строку более длинной строкой. (потому что мы используем \ r, мы остаемся на одной строке) Например:

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

То, что вы должны помнить, это когда вы закончите, если вы просто напечатаете

"done!\n"

У вас все еще может быть немного мусора из индикатора выполнения на линии. Поэтому после того, как вы закончили работу с индикатором выполнения, обязательно напечатайте достаточно пробелов, чтобы удалить его из строки. Такие как:

"done             |\n"

Надеюсь, это поможет.

31 голосов
/ 18 февраля 2018

Есть https://github.com/ctongfei/progressbar, Лицензия: MIT

Простой консольный индикатор выполнения. Запись индикатора выполнения теперь выполняется в другом потоке.

image

Для оптимальных визуальных эффектов рекомендуются Menlo, Fira Mono, Source Code Pro или SF Mono.

Для шрифтов Consolas или Andale Mono используйте ProgressBarStyle.ASCII (см. Ниже), поскольку глифы для рисования ящиков не выровнены должным образом в этих шрифтах.

image

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
22 голосов
/ 24 ноября 2009

Я нашел следующий код для правильной работы. Он записывает байты в выходной буфер. Возможно, что методы, использующие записывающее устройство, такое как метод 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 голосов
/ 13 апреля 2017

Я добился процентного прогресса, чтобы проверить оставшийся файл загрузки.

Я периодически вызываю метод при загрузке моего файла, чтобы проверить общий размер файла и оставшийся файл, и представляю его в %.

Может использоваться и для других задач.

Пример теста и вывода

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

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

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

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

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

Тест с циклом

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 голосов
/ 12 мая 2009

C # Пример, но я предполагаю, что это то же самое для System.out.print в Java. Не стесняйтесь поправлять меня, если я ошибаюсь.

По сути, вы хотите записать escape-символ \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();

    }
3 голосов
/ 23 апреля 2014

Вот модифицированная версия выше:

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 голосов
/ 13 февраля 2018

Я недавно столкнулся с той же проблемой, вы можете проверить мой код: Я установил его на один # на 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();
}
2 голосов
/ 23 мая 2013

Я использую «подпрыгивающий» индикатор выполнения, когда мне нужно отложить инструмент, чтобы предотвратить состояние гонки.

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 голосов
/ 12 мая 2009

Это было бы возможно с библиотекой Java Curses. Это - это то, что я нашел. Я сам этим не пользовался и не знаю, кросс-платформенный.

1 голос
/ 23 марта 2019

Немного переработан и обновлен метод @ 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");
        }
    }
...