Barra de progreso de línea de comando en Java

130

Tengo un programa Java que se ejecuta en modo de línea de comandos. Me gustaría mostrar una barra de progreso que muestre el porcentaje de trabajo realizado. El mismo tipo de barra de progreso que verías usando wget en Unix. es posible?

g andrieu
fuente
No sé la respuesta a su pregunta específica, pero podría comenzar revisando las bibliotecas mencionadas en esta pregunta: stackoverflow.com/questions/435740/…
Jonik
Gracias. Las bibliotecas citadas tienen más información sobre el análisis de argumentos de línea de comandos, en lugar de mostrarlas en la consola. Pero gracias de todos modos.
g andrieu
77
Esto es sobre el tema. OP pregunta si es posible, no para una recomendación de la biblioteca (al menos en la edición actual)
Neil McGuigan
¡Intento este código stackoverflow.com/questions/1001290/… y ejecuto ! (Correcto solo en la terminal, no lo use en Eclipse)
Wendel

Respuestas:

176

He implementado este tipo de cosas antes. No se trata tanto de Java, sino de qué personajes enviar a la consola.

La clave es la diferencia entre \ny \r. \nva al inicio de una nueva línea. Pero \res solo retorno de carro : vuelve al inicio de la misma línea.

Entonces, lo que hay que hacer es imprimir su barra de progreso, por ejemplo, imprimiendo la cadena

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

En el siguiente tic de la barra de progreso, sobrescriba la misma línea con una barra más larga. (porque estamos usando \ r, nos mantenemos en la misma línea) Por ejemplo:

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

Lo que debe recordar hacer es cuando termine, si simplemente imprime

"done!\n"

Es posible que aún tenga algo de basura de la barra de progreso en la línea. Entonces, una vez que haya terminado con la barra de progreso, asegúrese de imprimir suficiente espacio en blanco para eliminarlo de la línea. Como:

"done             |\n"

Espero que ayude.

Matthias Wandel
fuente
¿Es esto realmente multiplataforma? Probablemente se comportará bien en Windows y Linux, pero ¿qué pasa con las Mac? No tengo uno, así que no puedo probarlo ...
Radu Murzea
2
@RaduMurzea OS X es un * NIX OS, por lo que si funciona en Linux, funcionará en OS X (eso no es cierto para todo, pero es cierto aquí).
bfontaine
3
¡Gracias! Sin embargo, esto no funciona con Ant (probado tanto en Linux como en OSX; funciona bien cuando se invoca Java directamente). Alguien alguna idea?
user495285
Tenga en cuenta que esto no funciona en la consola integrada eclipse (al menos para mí). Pero como se trata de una consola de desarrollo, esto no debería importar demasiado.
Qw3ry
46

Hay https://github.com/ctongfei/progressbar , Licencia: MIT

Barra de progreso de consola simple. La escritura de la barra de progreso ahora se ejecuta en otro hilo.

Menlo, Fira Mono, Source Code Pro o SF Mono se recomiendan para obtener efectos visuales óptimos.

Para las fuentes Consolas o Andale Mono, use ProgressBarStyle.ASCII(vea a continuación) porque los glifos de dibujo de recuadro no están alineados correctamente en estas fuentes.

Maven

<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
koppor
fuente
1
esto se ve bien, y me permitirá reemplazar un par de cientos de líneas de búfer de cadena que tengo en mi CLI. Pero, ¿qué sucede si tengo una aplicación que se ejecuta durante minutos entre "ticks" (minutos entre step()llamadas)? ¿Su biblioteca se ejecuta de forma asíncrona, permitiendo que el reloj se actualice? ¿Qué pasa si mi biblioteca funciona durante días? ¿Utiliza la /restrategia? ¿Eso dará como resultado una salida de varios cientos de megabytes?
Groostav
23

Encontré el siguiente código para funcionar correctamente. Escribe bytes en el búfer de salida. Quizás los métodos que usan un escritor como el System.out.println()método reemplazan las ocurrencias de \ra \npara que coincidan con el final de la línea nativa del objetivo (si no está configurado correctamente).

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

He hecho un progreso porcentual desnudo para verificar el archivo de descarga restante.

Llamo al método periódicamente en la descarga de mi archivo para verificar el tamaño total del archivo y el resto y presentarlo en %.

También se puede usar para otros fines de tareas.

Ejemplo de prueba y salida

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

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

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

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

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

Prueba con bucle

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

El método se puede modificar fácilmente:

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-ɯɐɥʇʎɐɯ
fuente
5

Ejemplo de C # pero supongo que esto es lo mismo para System.out.printJava. Siéntase libre de corregirme si me equivoco.

Básicamente, desea escribir el \rcarácter de escape al comienzo de su mensaje, lo que hará que el cursor regrese al inicio de la línea (avance de línea) sin pasar a la siguiente línea.

    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
fuente
Un buen ejemplo, seguramente será útil. Gracias.
g andrieu
¡Hermoso! Gracias. Funciona como un encantador. Fácil de leer. Lovely
kholofelo Maloma
4

Un poco refactorizado y actualizado el método de @ maytham-ɯɐɥʇʎɐɯ. Ahora es compatible con un tamaño arbitrario de la barra de progreso:

    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");
        }
    }
Dennis
fuente
3

Aquí hay una versión modificada de lo anterior:

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

... y en general:

loading("Calculating ...");
usuario3563245
fuente
2

Esto sería posible con una biblioteca Java Curses. Esto es lo que he encontrado. No lo he usado yo mismo y no sé si es multiplataforma.

kgiannakakis
fuente
Las maldiciones pueden ser un poco costosas para el uso fácil que necesito, pero eso es seguro. Gracias.
g andrieu
2

Utilizo una barra de progreso de "rebote" cuando necesito retrasar una herramienta para evitar una condición de carrera.

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
fuente
2

Recientemente me he enfrentado al mismo problema, puedes verificar mi código: lo configuré para un # en 5%, que puedes modificar más adelante.

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
fuente
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
fuente
1

Edité el código de Eoin Campbell en Java y agregué progreso formateado en porcentajes.

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

Y salida:

Generating report...

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

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

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

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

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

Successfully saved 32128 bytes
Marko Štumberger
fuente
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
fuente
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
fuente
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()) + "]";
}

ingrese la descripción de la imagen aquí

Nikolay
fuente