Barre de progression de la ligne de commande en Java


130

J'ai un programme Java fonctionnant en mode ligne de commande. Je voudrais afficher une barre de progression, indiquant le pourcentage de travail effectué. Le même type de barre de progression que vous verriez en utilisant wget sous unix. Est-ce possible?


Je ne connais pas la réponse à votre question spécifique, mais vous pouvez commencer par vérifier les bibliothèques mentionnées dans cette question: stackoverflow.com/questions/435740/…
Jonik

Merci. Les bibliothèques citées ici concernent davantage l'analyse des arguments de ligne de commande que l'affichage dans la console. Mais merci quand même.
g andrieu

7
C'est sur le sujet. OP demande si possible, pas pour une recommandation de la bibliothèque (du moins dans l'édition actuelle)
Neil McGuigan

J'essaye ce code stackoverflow.com/questions/1001290/… et en cours d'exécution! (Exécution correcte uniquement dans le terminal, ne pas utiliser dans Eclipse)
Wendel

Réponses:


176

J'ai déjà implémenté ce genre de chose. Ce n'est pas tant une question de java, mais de quels caractères envoyer à la console.

La clé est la différence entre \net \r. \nva au début d'une nouvelle ligne. Mais ce \rn'est qu'un retour chariot - il revient au début de la même ligne.

Donc la chose à faire est d'imprimer votre barre de progression, par exemple, en imprimant la chaîne

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

Au prochain tick de la barre de progression, écrasez la même ligne par une barre plus longue. (parce que nous utilisons \ r, nous restons sur la même ligne) Par exemple:

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

Ce que vous devez vous rappeler de faire, c'est lorsque vous avez terminé, si vous imprimez simplement

"done!\n"

Vous pouvez toujours avoir des déchets de la barre de progression sur la ligne. Donc, une fois que vous avez terminé avec la barre de progression, assurez-vous d'imprimer suffisamment d'espaces pour la supprimer de la ligne. Tel que:

"done             |\n"

J'espère que cela pourra aider.


Est-ce vraiment multiplateforme? Il se comportera probablement correctement sous Windows et Linux, mais qu'en est-il des Mac? Je n'en ai pas, donc je ne peux pas l'essayer ...
Radu Murzea

2
@RaduMurzea OS X est un système d'exploitation * NIX, donc s'il fonctionne sous Linux, il fonctionnera sous OS X (ce n'est pas vrai pour tout, mais c'est vrai ici).
bfontaine le

3
Merci! Cependant, cela ne fonctionne pas avec ant (essayé à la fois sous linux et osx; fonctionne bien lors de l'appel direct de java). Quelqu'un a une idée?
user495285

Notez que cela ne fonctionne pas dans la console intégrée eclipse (du moins pour moi). Mais comme il s'agit d'une console de développement, cela ne devrait pas avoir trop d'importance.
Qw3ry


46

Il existe https://github.com/ctongfei/progressbar , Licence: MIT

Barre de progression de la console simple. L'écriture de la barre de progression s'exécute maintenant sur un autre thread.

Menlo, Fira Mono, Source Code Pro ou SF Mono sont recommandés pour des effets visuels optimaux.

Pour les polices Consolas ou Andale Mono, utilisez ProgressBarStyle.ASCII(voir ci-dessous) car les glyphes de dessin de boîte ne sont pas correctement alignés dans ces polices.

Maven:

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

Usage:

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
cela a l'air soigné, et cela me permettra de remplacer quelques centaines de lignes de tampon de chaîne que j'ai sur ma CLI. Mais que faire si j'ai une application qui fonctionne pendant des minutes entre les "ticks" (minutes entre les step()appels)? Votre bibliothèque fonctionne-t-elle de manière asynchrone, permettant ainsi à l'horloge de se mettre à jour? Et si ma bibliothèque fonctionnait pendant des jours? Utilise-t-il la /rstratégie? Cela entraînera-t-il une sortie de plusieurs centaines de mégaoctets?
Groostav

23

J'ai trouvé le code suivant pour fonctionner correctement. Il écrit des octets dans le tampon de sortie. Peut-être que les méthodes utilisant un rédacteur comme la System.out.println()méthode remplace les occurrences de \rto \npour correspondre à la fin de ligne native de la cible (si elle n'est pas configurée correctement).

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

J'ai fait un pourcentage de progrès à nu pour vérifier le fichier de téléchargement restant.

J'appelle la méthode périodiquement dans mon téléchargement de fichier pour vérifier la taille totale du fichier et la taille restante et la présenter au format %.

Il peut également être utilisé à d'autres fins.

Exemple de test et de sortie

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

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

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

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

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

Test avec boucle for

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

La méthode peut être facilement modifié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

Exemple C # mais je suppose que c'est la même chose pour System.out.printJava. N'hésitez pas à me corriger si je me trompe.

Fondamentalement, vous souhaitez écrire le \rcaractère d'échappement au début de votre message, ce qui fera revenir le curseur au début de la ligne (saut de ligne) sans passer à la ligne suivante.

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

    }

Bel exemple, sera certainement utile. Merci.
g andrieu

Belle! Je vous remercie. Fonctionne comme un charmeur. Facile à lire. Lovely
kholofelo Maloma

4

Un peu refactorisé et mis à jour la méthode de @ maytham-ɯɐɥʇʎɐɯ. Maintenant, il prend en charge une taille arbitraire de la barre de progression:

    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

Voici une version modifiée de ce qui précède:

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

... et en général:

loading("Calculating ...");

2

Cela serait possible avec une bibliothèque Java Curses. C'est ce que j'ai trouvé. Je ne l'ai pas utilisé moi-même et je ne sais pas si c'est multiplateforme.


Les malédictions peuvent être un peu trop lourdes pour l'utilisation facile dont j'ai besoin, mais c'est certainement une piste. Merci.
g andrieu

2

J'utilise une barre de progression "rebondissante" lorsque je dois retarder un outil pour éviter une condition de concurrence.

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

J'ai récemment rencontré le même problème, vous pouvez vérifier mon code: je l'ai défini pour un # sur 5%, que vous pourrez modifier plus tard.

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

J'ai édité le code d'Eoin Campbell en java et ajouté une progression formatée en pourcentages.

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

Et sortie:

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

entrez la description de l'image ici

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.