Индикатор выполнения командной строки в Java


130

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


Я не знаю ответа на ваш конкретный вопрос, но вы можете начать с проверки библиотек, упомянутых в этом вопросе: stackoverflow.com/questions/435740/…
Джоник

Спасибо. Процитированные там библиотеки больше посвящены синтаксическому анализу аргументов командной строки, чем отображению в консоли. Но все равно спасибо.
gandrieu

7
Это по теме. OP спрашивает, если возможно, не рекомендацию библиотеки (по крайней мере, в текущей редакции)
Нил МакГиган

Я пробую этот код stackoverflow.com/questions/1001290/… и запускаю! (Правильная работа только в терминале, не используйте в Eclipse)
Вендел

Ответы:


177

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

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

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

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

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

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

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

"done!\n"

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

"done             |\n"

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


Это действительно кроссплатформенный? Вероятно, он будет нормально себя вести в Windows и Linux, но как насчет Mac? У меня его нет, поэтому я не могу его попробовать ...
Раду Мурзеа

2
@RaduMurzea OS X - это ОС * NIX, поэтому, если она работает в Linux, она будет работать и в OS X (это верно не для всех, но это правда здесь).
bfontaine

3
Спасибо! Однако это не работает с ant (пробовал как на linux, так и на osx; отлично работает при прямом вызове java). Кто-нибудь есть идеи?
user495285

Обратите внимание, что это не работает в встроенной консоли eclipse (по крайней мере, для меня). Но поскольку это консоль разработки, это не должно иметь большого значения.
Qw3ry


46

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

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

Menlo, Fira Mono, Source Code 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

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. Не стесняйтесь поправлять меня, если я ошибаюсь.

По сути, вы хотите записать \rescape-символ в начало вашего сообщения, что приведет к тому, что курсор вернется в начало строки (Line Feed) без перехода к следующей строке.

    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();

    }

Хороший пример, безусловно, будет полезен. Спасибо.
gandrieu

Прекрасный! Спасибо. Работает как чародейка. Легко читать. Lovely
Холофело Малома 07

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

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

Я отредактировал код Эоина Кэмпбелла на 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()) + "]";
}

введите описание изображения здесь

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.