Pasek postępu wiersza poleceń w Javie

134

Mam program Java działający w trybie wiersza poleceń. Chciałbym wyświetlić pasek postępu, pokazujący procent wykonanej pracy. Ten sam rodzaj paska postępu, jaki zobaczysz używając wget pod unixem. czy to możliwe?

g andrieu
źródło
Nie znam odpowiedzi na Twoje konkretne pytanie, ale możesz zacząć od sprawdzenia bibliotek wymienionych w tym pytaniu: stackoverflow.com/questions/435740/…
Jonik
Dzięki. Cytowane tam biblioteki zawierają więcej informacji na temat analizowania argumentów wiersza poleceń, a nie ich wyświetlania w konsoli. Ale mimo wszystko dzięki.
g andrieu
8
To jest na temat. OP pyta, jeśli to możliwe, a nie o rekomendację biblioteki (przynajmniej w bieżącej edycji)
Neil McGuigan
Próbuję tego kodu stackoverflow.com/questions/1001290/ ... i działam! (Poprawne działanie tylko w terminalu, nie używaj w Eclipse)
Wendel

Odpowiedzi:

183

Wdrożyłem już tego typu rzeczy. Nie chodzi tu o Javę, ale o to, jakie znaki wysłać na konsolę.

Kluczem jest różnica między \ni \r. \nprzechodzi na początek nowej linii. Ale \rto tylko powrót karetki - wraca do początku tej samej linii.

Więc chodzi o wydrukowanie paska postępu, na przykład przez wydrukowanie ciągu

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

Przy następnym znaczniku paska postępu nadpisz tę samą linię dłuższym paskiem. (ponieważ używamy \ r, pozostajemy w tej samej linii) Na przykład:

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

To, o czym musisz pamiętać, jest po zakończeniu, jeśli po prostu drukujesz

"done!\n"

Nadal możesz mieć trochę śmieci z paska postępu w linii. Więc kiedy skończysz z paskiem postępu, upewnij się, że wypisałeś wystarczającą ilość spacji, aby usunąć go z wiersza. Jak na przykład:

"done             |\n"

Mam nadzieję, że to pomoże.

Matthias Wandel
źródło
Czy to naprawdę jest wieloplatformowa? Prawdopodobnie będzie się dobrze zachowywał w systemach Windows i Linux, ale co z komputerami Mac? Nie mam, więc nie mogę tego spróbować ...
Radu Murzea
3
@RaduMurzea OS X to system * NIX, więc jeśli działa na Linuksie, będzie działał na OS X (to nie jest prawdą dla wszystkiego, ale tak jest tutaj).
bfontaine
4
Dzięki! Jednak to nie działa z ant (próbowano zarówno na Linuksie, jak i na OSX; działa dobrze przy bezpośrednim wywołaniu javy). Czy ktoś ma pomysł?
user495285
Zauważ, że to nie działa w konsoli wbudowanej w eclipse (przynajmniej dla mnie). Ale ponieważ jest to konsola programistyczna, nie powinno to mieć większego znaczenia.
Qw3ry,
50

Jest https://github.com/ctongfei/progressbar , Licencja: MIT

Prosty pasek postępu konsoli. Pisanie na pasku postępu działa teraz w innym wątku.

W celu uzyskania optymalnych efektów wizualnych zalecane są Menlo, Fira Mono, Source Code Pro lub SF Mono.

W przypadku czcionek Consolas lub Andale Mono użyj ProgressBarStyle.ASCII(patrz poniżej), ponieważ glify do rysowania pudełek nie są prawidłowo wyrównane w tych czcionkach.

Maven:

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

Stosowanie:

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
koppor
źródło
2
wygląda to ładnie i pozwoli mi zastąpić kilkaset linii bufora łańcuchowego, które mam w moim CLI. Ale co, jeśli mam aplikację, która działa przez kilka minut między „taktami” (minutami między step()połączeniami)? Czy Twoja biblioteka działa asynchronicznie, co pozwala na aktualizację zegara? A jeśli moja biblioteka będzie działać przez kilka dni? Czy używa /rstrategii? Czy spowoduje to wieluset megabajtową produkcję?
Groostav
23

Uważam, że następujący kod działa poprawnie. Zapisuje bajty do bufora wyjściowego. Być może te metody wykorzystujące moduł zapisujący, taki jak System.out.println()metoda, zastępują wystąpienia \rdo, \naby dopasować natywne zakończenie wiersza celu (jeśli nie jest poprawnie skonfigurowane).

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);
        }
    }
}
keesj
źródło
9

Zrobiłem procentowy postęp, aby sprawdzić pozostały plik do pobrania.

Wywołuję tę metodę okresowo w moim pobieraniu pliku, aby sprawdzić całkowity rozmiar pliku i pozostały rozmiar i przedstawić go w %.

Może być również używany do innych celów.

Przykład testu i wyjścia

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

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

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

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

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

Przetestuj za pomocą pętli for

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

Metodę można łatwo zmodyfikować:

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");
    }
}
maytham-ɯɐɥʇʎɐɯ
źródło
5

Przykład C #, ale zakładam, że jest to to samo System.out.printw Javie. Możesz mnie poprawić, jeśli się mylę.

Zasadniczo chcesz wypisać \rznak ucieczki na początku wiadomości, co spowoduje, że kursor wróci na początek wiersza (przesunięcie o wiersz) bez przechodzenia do następnego wiersza.

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

    }
Eoin Campbell
źródło
Ładny przykład, na pewno będzie pomocny. Dzięki.
g andrieu
Piękny! Dziękuję Ci. Działa jak czarodziej. Łatwe do odczytania. Cudownie
kholofelo Maloma
4

Trochę refaktoryzowana i zaktualizowana metoda @ maytham-ɯɐɥʇʎɐɯ. Teraz obsługuje dowolny rozmiar paska postępu:

    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");
        }
    }
Denis
źródło
3

Oto zmodyfikowana wersja powyższego:

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

... a przede wszystkim:

loading("Calculating ...");
user3563245
źródło
2

Byłoby to możliwe dzięki bibliotece Java Curses. Oto, co znalazłem. Sam go nie używałem i nie wiem, czy jest to platforma wieloplatformowa.

kgiannakakis
źródło
Przekleństwa mogą być trochę narzutem dla łatwego użycia, którego potrzebuję, ale to z pewnością utwór. Dzięki.
g andrieu
2

Używam „odbijającego się” paska postępu, gdy muszę opóźnić narzędzie, aby zapobiec sytuacji wyścigu.

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");
}
mkeathley
źródło
2

Niedawno spotkałem się z tym samym problemem, możesz sprawdzić mój kod: ustawiłem go na jeden # na 5%, który możesz później zmodyfikować.

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();
}
Aashutosh Rathi
źródło
2

Edytowałem kod Eoina Campbella w Javie i dodałem sformatowany postęp w procentach.

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

I wyjście:

Generating report...

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

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

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

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

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

Successfully saved 32128 bytes
Marko Štumberger
źródło
Ten kod pokazuje procent w krokach, każdy krok to 3,33%. W przypadku, jeśli chcesz pokazać procent wykonanej pracy, wymienić String formattedPercent = String.format(" %5.1f %% ", (100 * currentProgressBarIndex) / (double) progressBarLength);zString formattedPercent = String.format(" %7.3f %% ", (100 * currentValue) / (double) maxValue);
izogfif
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();
    }
vootla561
źródło
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");
    }
}
Lurzapps
źródło
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);
        }

        }

    }
Arun Joshla
źródło
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()) + "]";
}

wprowadź opis obrazu tutaj

Nikolay
źródło