72

I want to print a progress bar like so:

[#                    ] 1%
[##                   ] 10%
[##########           ] 50%

But these should all be printed to the same line in the terminal instead of a new one. What I mean by that is that each new line should replace the previous, it's not about using print() instead of println().

How can I do that in Java?

Aillyn
  • 23,354
  • 24
  • 59
  • 84

8 Answers8

116

Format your string like so:

[#                    ] 1%\r

Note the \r character. It is the so-called carriage return that will move the cursor back to the beginning of the line.

Finally, make sure you use

System.out.print()

and not

System.out.println()
Konstantinos Margaritis
  • 3,237
  • 3
  • 22
  • 32
NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • 20
    The carriage return escape sequence `\r` doesn't work in Eclipse because of an [old bug](https://bugs.eclipse.org/bugs/show_bug.cgi?id=76936) reported in 2004 and not fixed yet in the last version of Eclipse (4.3.2 Kepler) – Marco Lackovic Mar 05 '14 at 15:35
  • @Sortofabeginner: In a word, yes. – NPE Apr 04 '14 at 06:22
  • 2
    @Krige: The same applies with the output pane in Netbeans 8, at least on my Mac. The `\r` character is interpreted as a newline. VT100 codes and backspaces don't work correctly either, unfortunately. – Desty Sep 24 '14 at 14:05
  • 1
    @Marco Lackovic: also tried it on eclipse neon 4.6.0, still doesn't work (interpreted as a new line.) – SubMachine Dec 02 '18 at 20:31
  • 4
    @MarcoLackovic The bug in Eclipse is fixed (since 2020-03). As pointed out in https://stackoverflow.com/a/62108112/3427883, you basically need to Window ➺ Preferences ➺ Run/Debug ➺ Console, then check the two check-boxes 'Interpret ASCII...' and 'Interpret Carriage Return (\r) as' – Abdu Jul 07 '20 at 14:57
15

In Linux, there is different escape sequences for control terminal. For example, there is special escape sequence for erase whole line: \33[2K and for move cursor to previous line: \33[1A. So all you need is to print this every time you need to refresh the line. Here is the code which prints Line 1 (second variant):

System.out.println("Line 1 (first variant)");
System.out.print("\33[1A\33[2K");
System.out.println("Line 1 (second variant)");

There are codes for cursor navigation, clearing screen and so on.

I think there are some libraries which helps with it (ncurses?).

csonuryilmaz
  • 1,715
  • 24
  • 24
Kirill
  • 3,364
  • 2
  • 21
  • 36
  • 3
    I've written a couple utility classes for automating this task for you; they include colourising the output as well: http://bitbucket.org/dainkaplan/tempura-utils – DK_ Jun 04 '13 at 03:34
14

First, I'd like to apologize for bringing this question back up, but I felt that it could use another answer.

Derek Schultz is kind of correct. The '\b' character moves the printing cursor one character backwards, allowing you to overwrite the character that was printed there (it does not delete the entire line or even the character that was there unless you print new information on top). The following is an example of a progress bar using Java though it does not follow your format, it shows how to solve the core problem of overwriting characters (this has only been tested in Ubuntu 12.04 with Oracle's Java 7 on a 32-bit machine, but it should work on all Java systems):

public class BackSpaceCharacterTest
{
    // the exception comes from the use of accessing the main thread
    public static void main(String[] args) throws InterruptedException
    {
        /*
            Notice the user of print as opposed to println:
            the '\b' char cannot go over the new line char.
        */
        System.out.print("Start[          ]");
        System.out.flush(); // the flush method prints it to the screen

        // 11 '\b' chars: 1 for the ']', the rest are for the spaces
        System.out.print("\b\b\b\b\b\b\b\b\b\b\b");
        System.out.flush();
        Thread.sleep(500); // just to make it easy to see the changes

        for(int i = 0; i < 10; i++)
        {
            System.out.print("."); //overwrites a space
            System.out.flush();
            Thread.sleep(100);
        }

        System.out.print("] Done\n"); //overwrites the ']' + adds chars
        System.out.flush();
    }
}
Amndeep7
  • 2,022
  • 4
  • 17
  • 26
3

You could print the backspace character '\b' as many times as necessary to delete the line before printing the updated progress bar.

Derek Schultz
  • 63
  • 1
  • 5
2
package org.surthi.tutorial.concurrency;

public class IncrementalPrintingSystem {
    public static void main(String...args) {
        new Thread(()-> {
           int i = 0;
           while(i++ < 100) {
               System.out.print("[");
               int j=0;
               while(j++<i){
                  System.out.print("#");
               }
               while(j++<100){
                  System.out.print(" ");
               }
               System.out.print("] : "+ i+"%");
               try {
                  Thread.sleep(1000l);
               } catch (InterruptedException e) {
                  e.printStackTrace();
               }
               System.out.print("\r");
           }
        }).start();
    }
}
Striped
  • 2,544
  • 3
  • 25
  • 31
2

One could simply use \r to keep everything in the same line while erasing what was previously on that line.

Amiothenes
  • 41
  • 2
1

In kotlin

print()

The print statement prints everything inside it onto the screen. The print statements internally call System.out.print.

println()

The println statement appends a newline at the end of the output.

Ajay Deepak
  • 471
  • 5
  • 9
-3

You can just do

System.out.print("String");

Instead

System.out.println("String");
Mosrur
  • 1
  • 1
    This is not a correct answer. Notice that the question includes this at the end: "What I mean by that is that each new line should replace the previous, it's not about using `print()` instead of `println()`." – Jonathan E. Landrum Apr 20 '20 at 19:35