Befehlszeilen-Fortschrittsbalken in Java


130

Ich habe ein Java-Programm, das im Befehlszeilenmodus ausgeführt wird. Ich möchte einen Fortschrittsbalken anzeigen, der den Prozentsatz der geleisteten Arbeit anzeigt. Dieselbe Art von Fortschrittsbalken, die Sie mit wget unter Unix sehen würden. Ist das möglich?


Ich kenne die Antwort auf Ihre spezielle Frage nicht, aber Sie können zunächst die in dieser Frage genannten Bibliotheken überprüfen: stackoverflow.com/questions/435740/…
Jonik

Vielen Dank. In den dort zitierten Bibliotheken geht es mehr um das Parsen von Befehlszeilenargumenten als um die Anzeige in der Konsole. Aber trotzdem danke.
g andrieu

7
Das ist zum Thema. OP fragt nach Möglichkeit, nicht nach einer Bibliotheksempfehlung (zumindest in der aktuellen Ausgabe)
Neil McGuigan

Ich versuche diesen Code stackoverflow.com/questions/1001290/… und laufe ! (Korrekte Ausführung nur im Terminal, nicht in Eclipse verwenden)
Wendel

Antworten:


176

Ich habe so etwas schon einmal implementiert. Es geht nicht so sehr um Java, sondern darum, welche Zeichen an die Konsole gesendet werden sollen.

Der Schlüssel ist der Unterschied zwischen \nund \r. \ngeht zum Anfang einer neuen Zeile. Ist \raber nur Wagenrücklauf - es geht zurück zum Anfang der gleichen Zeile.

Sie müssen also Ihren Fortschrittsbalken drucken, indem Sie beispielsweise die Zeichenfolge drucken

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

Überschreiben Sie beim nächsten Häkchen des Fortschrittsbalkens dieselbe Zeile mit einem längeren Balken. (Da wir \ r verwenden, bleiben wir in derselben Zeile.) Zum Beispiel:

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

Was Sie beachten müssen, ist, wenn Sie fertig sind, wenn Sie dann nur drucken

"done!\n"

Möglicherweise haben Sie noch Müll aus dem Fortschrittsbalken in der Zeile. Wenn Sie mit dem Fortschrittsbalken fertig sind, müssen Sie genügend Leerzeichen drucken, um ihn aus der Zeile zu entfernen. Sowie:

"done             |\n"

Hoffentlich hilft das.


Ist das wirklich plattformübergreifend? Es wird sich unter Windows und Linux wahrscheinlich in Ordnung verhalten, aber was ist mit Macs? Ich habe keine, also kann ich es nicht versuchen ...
Radu Murzea

2
@RaduMurzea OS X ist ein * NIX-Betriebssystem. Wenn es also unter Linux funktioniert, funktioniert es unter OS X (das gilt nicht für alles, aber das gilt hier).
Bfontaine

3
Vielen Dank! Dies funktioniert jedoch nicht mit ant (versucht sowohl unter Linux als auch unter osx; funktioniert gut, wenn Java direkt aufgerufen wird). Hat jemand eine Idee?
user495285

Beachten Sie, dass dies in der in Eclipse integrierten Konsole nicht funktioniert (zumindest für mich). Da dies jedoch eine Entwicklungskonsole ist, sollte dies nicht allzu wichtig sein.
Qw3ry


46

Es gibt https://github.com/ctongfei/progressbar , Lizenz: MIT

Einfache Konsolen-Fortschrittsanzeige. Das Schreiben des Fortschrittsbalkens wird jetzt in einem anderen Thread ausgeführt.

Für optimale visuelle Effekte werden Menlo, Fira Mono, Source Code Pro oder SF Mono empfohlen.

Verwenden Sie für Consolas- oder Andale Mono-Schriftarten ProgressBarStyle.ASCII(siehe unten), da die Glyphen zum Zeichnen von Kästchen in diesen Schriftarten nicht richtig ausgerichtet sind.

Maven:

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

Verwendung:

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
Das sieht ordentlich aus und ermöglicht es mir, ein paar hundert String-Buffer-Zeilen zu ersetzen, die ich auf meiner CLI habe. Aber was ist, wenn ich eine Anwendung habe, die Minuten zwischen "Ticks" (Minuten zwischen step()Anrufen) läuft ? Läuft Ihre Bibliothek asynchron, sodass die Uhr aktualisiert werden kann? Was ist, wenn meine Bibliothek tagelang läuft? Verwendet es die /rStrategie? Wird dies zu einer Ausgabe von mehreren hundert Megabyte führen?
Groostav

23

Ich habe festgestellt, dass der folgende Code korrekt funktioniert. Es schreibt Bytes in den Ausgabepuffer. Möglicherweise ersetzt diese Methode, die einen Writer wie die System.out.println()Methode verwendet, das Vorkommen von \rto \n, um mit dem nativen Zeilenende des Ziels übereinzustimmen (falls nicht richtig konfiguriert).

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

Ich habe einen prozentualen Fortschritt gemacht, um die verbleibende Download-Datei zu überprüfen.

Ich rufe die Methode regelmäßig in meinem Dateidownload auf, um die gesamte Dateigröße und die verbleibende zu überprüfen und diese in zu präsentieren %.

Es kann auch für andere Aufgaben verwendet werden.

Test- und Ausgabebeispiel

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

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

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

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

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

Test mit for-Schleife

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

Die Methode kann leicht geändert werden:

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 # Beispiel, aber ich gehe davon aus, dass dies System.out.printin Java dasselbe ist . Fühlen Sie sich frei, mich zu korrigieren, wenn ich falsch liege.

Grundsätzlich möchten Sie das \rEscape-Zeichen an den Anfang Ihrer Nachricht schreiben, wodurch der Cursor zum Zeilenanfang (Zeilenvorschub) zurückkehrt, ohne zur nächsten Zeile zu wechseln.

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

    }

Schönes Beispiel, wird sicher hilfreich sein. Vielen Dank.
g andrieu

Wunderschönen! Danke dir. Funktioniert wie ein Charmeur. Leicht zu lesen. Schöne
kholofelo MALOMA

4

Ein bisschen überarbeitet und aktualisiert @ maytham-ɯɐɥʇʎɐɯ 's Methode. Jetzt unterstützt es eine beliebige Größe des Fortschrittsbalkens:

    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

Hier ist eine modifizierte Version des oben genannten:

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

... und hauptsächlich:

loading("Calculating ...");

2

Dies wäre mit einer Java Curses-Bibliothek möglich. Das habe ich gefunden. Ich habe es selbst nicht benutzt und weiß nicht, ob es plattformübergreifend ist.


Flüche mögen für die einfache Verwendung, die ich brauche, ein bisschen Overhead sein, aber das ist sicher eine Spur. Vielen Dank.
Andrieu

2

Ich verwende einen "springenden" Fortschrittsbalken, wenn ich ein Werkzeug verzögern muss, um eine Rennbedingung zu verhindern.

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

Ich hatte kürzlich das gleiche Problem. Sie können meinen Code überprüfen: Ich habe ihn auf 5% gesetzt, was Sie später ändern können.

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

Ich habe den Code von Eoin Campbell in Java bearbeitet und den formatierten Fortschritt in Prozent hinzugefügt.

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

Und Ausgabe:

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

Geben Sie hier die Bildbeschreibung ein

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.