Barra di avanzamento della riga di comando in Java


130

Ho un programma Java in esecuzione in modalità riga di comando. Vorrei visualizzare una barra di avanzamento, che mostra la percentuale di lavoro svolto. Lo stesso tipo di barra di avanzamento che vedresti usando wget sotto unix. È possibile?


Non conosco la risposta alla tua domanda specifica, ma si potrebbe iniziare controllando le librerie menzionate in questa domanda: stackoverflow.com/questions/435740/...
Jonik

Grazie. Le librerie citate sono più sull'analisi degli argomenti della riga di comando, piuttosto che sulla console. Ma grazie comunque.
g andrieu,

7
Questo è in tema. OP chiede se possibile, non per una raccomandazione della biblioteca (almeno nella modifica attuale)
Neil McGuigan,

Provo questo codice stackoverflow.com/questions/1001290/… e funzionante! (Corretto solo nel terminale, non usare in Eclipse)
Wendel,

Risposte:


176

Ho implementato questo genere di cose prima. Non si tratta tanto di Java, ma di quali personaggi inviare alla console.

La chiave è la differenza tra \ne \r. \nva all'inizio di una nuova linea. Ma \rè solo il ritorno in carrozza a capo: torna all'inizio della stessa riga.

Quindi la cosa da fare è stampare la barra di avanzamento, ad esempio stampando la stringa

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

Sul segno di spunta successivo della barra di avanzamento, sovrascrivere la stessa riga con una barra più lunga. (poiché stiamo usando \ r, rimaniamo sulla stessa riga) Ad esempio:

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

Quello che devi ricordare di fare è quando hai finito, se poi semplicemente stampi

"done!\n"

Potresti avere ancora dei rifiuti dalla barra di avanzamento sulla linea. Quindi, dopo aver finito con la barra di avanzamento, assicurati di stampare abbastanza spazio per rimuoverlo dalla linea. Ad esempio:

"done             |\n"

Spero che aiuti.


È davvero multipiattaforma? Probabilmente si comporterà bene su Windows e Linux, ma per quanto riguarda i Mac? Non ne ho uno, quindi non posso provarlo ...
Radu Murzea,

2
@RaduMurzea OS X è un sistema operativo * NIX, quindi se funziona su Linux, funzionerà su OS X (non è vero per tutto, ma è vero qui).
bfontaine,

3
Grazie! Tuttavia, questo non funziona con ant (provato sia su Linux che su OSX; funziona bene quando si richiama direttamente Java). Qualcuno ha qualche idea?
user495285,

Nota che questo non funziona nella console integrata di eclipse (almeno per me). Ma poiché si tratta di una console di sviluppo, non dovrebbe importare troppo.
Qw3ry,


46

C'è https://github.com/ctongfei/progressbar , Licenza: MIT

Barra di avanzamento della console semplice. La scrittura della barra di avanzamento ora viene eseguita su un altro thread.

Menlo, Fira Mono, Source Code Pro o SF Mono sono raccomandati per effetti visivi ottimali.

Per i caratteri Consolas o Andale Mono, utilizzare ProgressBarStyle.ASCII(vedere di seguito) perché i glifi di disegno a riquadri non sono allineati correttamente in questi caratteri.

Esperto di:

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

Uso:

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
questo sembra pulito e mi permetterà di sostituire un paio di centinaia di righe di buffer di stringa che ho sulla mia CLI. E se avessi un'applicazione che funziona per minuti tra "tick" (minuti tra step()chiamate)? La tua libreria funziona in modo asincrono, permettendo così all'orologio di aggiornarsi? Cosa succede se la mia biblioteca funziona per giorni? Usa la /rstrategia? Ciò si tradurrà in output da più di cento megabyte?
Groostav,

23

Ho trovato il seguente codice per funzionare correttamente. Scrive byte nel buffer di output. Forse quei metodi che usano uno scrittore come il System.out.println()metodo sostituiscono le occorrenze di \rto \nper abbinare la fine della linea nativa del bersaglio (se non configurata correttamente).

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

Ho fatto un progresso percentuale nudo per verificare il file di download rimanente.

Chiamo periodicamente il metodo nel download del mio file per verificare la dimensione totale del file, rimanendo e presentandolo %.

Può essere utilizzato anche per altri scopi.

Esempio di test e output

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

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

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

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

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

Prova con per loop

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

Il metodo può essere facilmente modificato:

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

Esempio C # ma suppongo che sia lo stesso per System.out.printJava. Sentiti libero di correggermi se sbaglio.

Fondamentalmente, si desidera scrivere il \rcarattere di escape all'inizio del messaggio, in modo che il cursore ritorni all'inizio della riga (avanzamento riga) senza spostarsi alla riga successiva.

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

    }

Un bell'esempio, sarà sicuramente utile. Grazie.
g andrieu,

Bellissimo! Grazie. Funziona come un incantatore. Facile da leggere. Adorabile
kholofelo Maloma il

4

Un po 'refactored e aggiornato il metodo di @ maytham-ɯɐɥʇʎɐɯ. Ora supporta una dimensione arbitraria della barra di avanzamento:

    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

Ecco una versione modificata di quanto sopra:

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

... e principalmente:

loading("Calculating ...");

2

Ciò sarebbe possibile con una libreria Java Curses. Questo è quello che ho trovato. Non l'ho usato da solo e non so se sia multipiattaforma.


Le maledizioni possono essere un po 'impegnative per il facile utilizzo di cui ho bisogno, ma sicuramente è una traccia. Grazie.
g andrieu,

2

Uso una barra di avanzamento "che rimbalza" quando devo ritardare uno strumento per prevenire una condizione di gara.

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

Di recente ho riscontrato lo stesso problema, puoi controllare il mio codice: l'ho impostato per un # al 5%, che puoi modificare in seguito.

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

Ho modificato il codice di Eoin Campbell su java e ho aggiunto progressi formattati in percentuale.

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

E uscita:

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

inserisci qui la descrizione dell'immagine

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.