Java: Updating text in the command-line without a new line

39,635

Solution 1

First when you write, don't use writeln(). Use write(). Second, you can use a "\r" to Carriage Return without using \n which is a New line. The carriage return should put you back at the beginning of the line.

Solution 2

I use following code:

public static void main(String[] args) {
    long total = 235;
    long startTime = System.currentTimeMillis();

    for (int i = 1; i <= total; i = i + 3) {
        try {
            Thread.sleep(50);
            printProgress(startTime, total, i);
        } catch (InterruptedException e) {
        }
    }
}


private static void printProgress(long startTime, long total, long current) {
    long eta = current == 0 ? 0 : 
        (total - current) * (System.currentTimeMillis() - startTime) / current;

    String etaHms = current == 0 ? "N/A" : 
            String.format("%02d:%02d:%02d", TimeUnit.MILLISECONDS.toHours(eta),
                    TimeUnit.MILLISECONDS.toMinutes(eta) % TimeUnit.HOURS.toMinutes(1),
                    TimeUnit.MILLISECONDS.toSeconds(eta) % TimeUnit.MINUTES.toSeconds(1));

    StringBuilder string = new StringBuilder(140);   
    int percent = (int) (current * 100 / total);
    string
        .append('\r')
        .append(String.join("", Collections.nCopies(percent == 0 ? 2 : 2 - (int) (Math.log10(percent)), " ")))
        .append(String.format(" %d%% [", percent))
        .append(String.join("", Collections.nCopies(percent, "=")))
        .append('>')
        .append(String.join("", Collections.nCopies(100 - percent, " ")))
        .append(']')
        .append(String.join("", Collections.nCopies((int) (Math.log10(total)) - (int) (Math.log10(current)), " ")))
        .append(String.format(" %d/%d, ETA: %s", current, total, etaHms));

    System.out.print(string);
}

The result: enter image description here

Share:
39,635
Tom Marthenal
Author by

Tom Marthenal

Updated on July 09, 2022

Comments

  • Tom Marthenal
    Tom Marthenal almost 2 years

    I'd like to add a progress indicator to a command-line Java program.

    For example, if I'm using wget, it shows:

    71% [===========================>           ] 358,756,352 51.2M/s  eta 3s
    

    Is it possible to have a progress indicator that updates without adding a new line to the bottom?

    Thanks.

  • jstanley
    jstanley over 13 years
    But if the length of text can possibly shrink (for example, the number of digits required to display the ETA decreases), remember to write spaces over the old characters so that they don't show up any more. EDIT: In addition, remember to do System.out.flush() to make sure the text actually shows up (e.g. on a line-buffered terminal).
  • Cardinal System
    Cardinal System about 6 years
    I used \r, but it is acting like \n. I am using print instead of println. Any idea why it's not working?
  • newsha
    newsha about 6 years
    @CardinalSystem - Using eclipse console by any chance? Apparently it does not handle \r correctly. It will work in java cli though.
  • Cardinal System
    Cardinal System about 6 years
    @newsha ah, that seems to be the case. Thank you!
  • PhDeveloper
    PhDeveloper over 5 years
    I tried that in Eclipse but it prints each progress on a new line. I added the following command before System.out.print(string); and it fixed the problem: System.out.println(new String(new char[70]).replace("\0", "\r\n")); Basically this clears Eclipse console so it looks like the line is being updated.
  • Danon
    Danon about 5 years
    @PhDeveloper Yea, Eclipse is broken. In 100 articles about console, you'll find a note: "Works in every terminal but eclipse".
  • derHugo
    derHugo almost 5 years
    I had quite huge values (bytewise file upload) so instead of the int percent = (int) (current * 100 / total); I had to use int percent = (int) (((float)current / (float)total) * 100); in order to avoid integer overflow.
  • Saurav Kumar
    Saurav Kumar over 4 years
    Does it depend on size of terminal window??
  • propatience
    propatience over 2 years
    @Danon Well it doesn't work by default in Eclipse but it does if you change the setting. Look here stackoverflow.com/a/64968642/6533028
  • bhlowe
    bhlowe about 2 years
    If you call it with current = 0, (no progress) the log10 of zero is undefined/infinity. Which causes a crash on the second to last append line. Other than that, super handy!