Рядок прогресу командного рядка на Java


130

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


Я не знаю відповіді на ваше конкретне питання, але ви можете почати, перевіривши бібліотеки, згадані в цьому запитанні: stackoverflow.com/questions/435740/…
Jonik,

Дякую. Цитовані бібліотеки більше стосуються розбору аргументів командного рядка, а не відображення в консолі. Але дякую все одно.
g andrieu

7
Це на тему. ОП просить, якщо можливо, не щодо рекомендацій щодо бібліотеки (принаймні в поточній редакції)
Ніл МакГуйган

Я пробую цей код stackoverflow.com/questions/1001290/… і працює! (Правильно працює лише в терміналі, не використовуйте в Eclipse)
Wendel

Відповіді:


176

Я реалізував подібні речі раніше. Йдеться не стільки про java, скільки про те, які символи потрібно надіслати на консоль.

Ключовою є різниця між \nі \r. \nпереходить до початку нового рядка. Але \rце лише повернення вагона - воно повертається до початку тієї ж лінії.

Тому потрібно надрукувати смужку прогресу, наприклад, надрукувавши рядок

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

На наступній галочці панелі прогресу перезапишіть ту саму лінію довшою смужкою. (оскільки ми використовуємо \ r, ми залишаємося в одній лінії) Наприклад:

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

Що потрібно пам’ятати - це коли це зроблено, якщо ви просто друкуєте

"done!\n"

Можливо, у вас ще є сміття з панелі прогресу на лінії. Тож після того, як ви закінчите з панеллю прогресу, обов’язково надрукуйте достатньо пробілів, щоб видалити його з рядка. Як от:

"done             |\n"

Сподіваюся, що це допомагає.


Це справді кросплатформа? Напевно, це буде добре в Windows та Linux, але що робити з Mac? У мене його немає, тому я не можу спробувати його ...
Radu Murzea

2
@RaduMurzea OS X - це * NIX OS, тому якщо він працює на Linux, він буде працювати на OS X (це не правда для всього, але це правда тут).
bfontaine

3
Дякую! Однак це не спрацьовує з мурахами (пробували як на Linux, так і на OSX; добре працює при безпосередньому виклику Java). Хтось має ідею?
user495285

Зауважте, що це не працює в затемненому вбудованому консолі (принаймні для мене). Але оскільки це консоль розробки, це не повинно мати великого значення.
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стратегію? Чи призведе це до виходу багатосот мегабайт?
Гроостав

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

Гарний! Дякую. Працює як чарівник. Легко читати. Lovely
холофело Малома

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.