Barra de progresso da linha de comandos em Java

130

Eu tenho um programa Java em execução no modo de linha de comando. Gostaria de exibir uma barra de progresso, mostrando a porcentagem de trabalho realizado. O mesmo tipo de barra de progresso que você veria usando o wget no unix. Isso é possível?

g andrieu
fonte
Eu não sei a resposta à sua pergunta específica, mas você pode começar por verificar as bibliotecas mencionadas nesta questão: stackoverflow.com/questions/435740/...
Jonik
Obrigado. As bibliotecas citadas são mais sobre a análise de argumentos da linha de comandos, em vez de serem exibidas no console. Mas obrigado de qualquer maneira.
g andrieu
7
Isso está no tópico. OP pergunta se possível, não para uma recomendação biblioteca (pelo menos na edição atual)
Neil McGuigan
Eu tento esse código stackoverflow.com/questions/1001290/… e em execução! (Em execução correta apenas em terminal, não usar em Eclipse)
Wendel

Respostas:

176

Eu já implementei esse tipo de coisa antes. Não é muito sobre java, mas quais caracteres enviar para o console.

A chave é a diferença entre \ne \r. \nvai para o início de uma nova linha. Mas \ré apenas o retorno de carro - ele volta ao início da mesma linha.

Portanto, o que você deve fazer é imprimir sua barra de progresso, por exemplo, imprimindo a string

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

No próximo tique da barra de progresso, substitua a mesma linha por uma barra mais longa. (porque estamos usando \ r, permanecemos na mesma linha) Por exemplo:

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

O que você precisa se lembrar de fazer é quando terminar, se você apenas imprimir

"done!\n"

Você ainda pode ter algum lixo da barra de progresso na linha. Portanto, depois de concluir a barra de progresso, imprima espaço em branco suficiente para removê-la da linha. Tal como:

"done             |\n"

Espero que ajude.

Matthias Wandel
fonte
Isso é realmente multiplataforma? Provavelmente se comportará bem no Windows e Linux, mas e os Macs? Eu não tenho um, então eu não posso tentar ...
Radu Murzea
2
O @RaduMurzea OS X é um * NIX OS; portanto, se funcionar no Linux, funcionará no OS X (isso não é verdade para tudo, mas é verdade aqui).
bfontaine
3
Obrigado! No entanto, isso não funciona com o ant (tentado no linux e no osx; funciona bem ao invocar o java diretamente). Alguém tem alguma ideia?
User495285
Observe que isso não funciona no eclipse embutido no console (pelo menos para mim). Mas como este é um console de desenvolvimento, isso não deve importar muito.
Qw3ry
Eu encontrei esta: stackoverflow.com/questions/1001290/...
Wendel
46

Existe https://github.com/ctongfei/progressbar , Licença: MIT

Barra de progresso simples do console. A gravação da barra de progresso agora é executada em outro segmento.

Menlo, Fira Mono, Source Code Pro ou SF Mono são recomendados para efeitos visuais ideais.

Para fontes Consolas ou Andale Mono, use ProgressBarStyle.ASCII(veja abaixo) porque os glifos de desenho de caixa não estão alinhados corretamente nessas fontes.

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
fonte
1
isso parece legal e me permitirá substituir algumas centenas de linhas de buffer de string que tenho na minha CLI. Mas e se eu tiver um aplicativo que seja executado por minutos entre "ticks" (minutos entre step()chamadas)? Sua biblioteca é executada de forma assíncrona, permitindo que o relógio seja atualizado? E se minha biblioteca funcionar por dias? Ele usa a /restratégia? Isso resultará em uma saída de centenas de megabytes?
Groostav
23

Encontrei o seguinte código para funcionar corretamente. Ele grava bytes no buffer de saída. Talvez os métodos que usam um gravador como o System.out.println()método substituam as ocorrências de \rto \npara coincidir com o final da linha nativa do destino (se não estiver configurado corretamente).

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

Fiz um progresso percentual para verificar o restante do arquivo baixado.

Chamo o método periodicamente no download do meu arquivo para verificar o tamanho total do arquivo e o restante e apresentá-lo em %.

Também pode ser usado para outros fins de tarefa.

Exemplo de teste e saída

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

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

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

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

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

Teste com loop for

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

O método pode ser facilmente modificado:

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

Exemplo de c #, mas estou assumindo que isso é o mesmo para System.out.printem Java. Sinta-se livre para me corrigir se eu estiver errado.

Basicamente, você deseja escrever o \rcaractere de escape no início da sua mensagem, o que fará com que o cursor retorne ao início da linha (avanço de linha) sem passar para a próxima linha.

    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
fonte
Bom exemplo, com certeza será útil. Obrigado.
g andrieu
Lindo! Obrigado. Funciona como um encantador. Fácil de ler. Adorável
kholofelo Maloma 07/07/16
4

Um pouco refatorado e atualizado o método de @ maytham-ɯɐɥʇʎɐɯ. Agora está suportando um tamanho arbitrário da barra de progresso:

    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
fonte
3

Aqui está uma versão modificada do acima:

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 ...");
user3563245
fonte
2

Isso seria possível com uma biblioteca Java Curses. Isto é o que eu encontrei. Eu não o usei e não sei se é multiplataforma.

kgiannakakis
fonte
As maldições podem ser um pouco exageradas para o uso fácil de que preciso, mas essa certeza é uma pista. Obrigado.
g andrieu
2

Eu uso uma barra de progresso "quicando" quando preciso atrasar uma ferramenta para evitar uma condição de corrida.

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

Recentemente, enfrentei o mesmo problema, você pode verificar meu código: configurei-o para um # em 5%, que você pode modificar posteriormente.

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

Editei o código de Eoin Campbell para java e adicionei o progresso formatado em porcentagens.

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 saída:

Generating report...

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

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

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

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

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

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

insira a descrição da imagem aqui

Nikolay
fonte