5

I'm trying to make a cross platform console progress indicator in Java. Therefore I use the System.out.printf method to print out a percentage:

System.out.printf("\t%2.2f%%\b\b\b\b\b\b", percentage);

and I place this in a for loop. The problem I encounter is that it's not printing anything until the whole for loop is done. This is a program example to show the problem:

public class Test {

    public static void main(String[] args) {
        for(int i =0; i<5000; i++){
            System.out.printf("\b\b\b\b\b\b%2.2f%%", ((float) i/5000f)*100f);
            System.out.flush();
        }
    }
}

I think the problem has something to do with compiler optimisation, but I'm not shure. The strange thing is that System.out.println does print when the for loop is running.

Edit: I forgot to add it to the problem. But I had allready tried to flush the buffer. This makes no difference. Adding %n to the end of my printf line works but it starts a newline, I really need it to reuse the current line.

All opposed solutions work. But they only work in real consoles. Not the netbeans or eclipse console.

Daan Pape
  • 1,100
  • 1
  • 13
  • 25
  • Your code works for me, but is a bit fast, so I included a `try { Thread.sleep (10); } catch (InterruptedException ignored) {}`. – user unknown Mar 24 '12 at 16:52

4 Answers4

7

That's because the output stream is line buffered. If you add a "%n" at the end of your format string you also generate a line break and the line will be flushed (i.e. printed). Alternatively call System.out.flush() to manually flush the output stream and force buffered contents to be printed.

user268396
  • 11,576
  • 2
  • 31
  • 26
2

And once more the problem is with flushing the stream. Add this line after your printf:

System.out.flush();

System.out.println is flushing (much like C++'s << endl). However, printf is not flushing and is using buffer.

Boris Strandjev
  • 46,145
  • 15
  • 108
  • 135
  • Flush is method so you need brackets for sure. – Boris Strandjev Mar 24 '12 at 15:16
  • I had added brackets in my original code, I see they were not copied. I fixed it in the starting post. The problem is still not solved. – Daan Pape Mar 24 '12 at 15:17
  • and what is the goal to replace the old characters with the new ones so you get something similar to counter? – Boris Strandjev Mar 24 '12 at 15:19
  • I want to make a progress indicator. When I have like 5000 steps to calculate I don't want to print out 5000 lines but only one line showing the percentage of how much has been processed allready. – Daan Pape Mar 24 '12 at 15:27
  • Thank you for the help. It turns out it was the console from netbeans that didn't respond as a normal console. – Daan Pape Mar 24 '12 at 15:45
  • You should have tried the Eclipse console. I needed to resort to command line in order to test your code. – Boris Strandjev Mar 24 '12 at 15:46
1

Add a call to flush():

    for(int i =0; i<5000; i++){
        System.out.printf("\b\b\b\b\b\b%2.2f%%", ((float) i/5000f)*100f);
        System.out.flush();
    }

Without the flush(), the output gets accumulated in a buffer that only gets flushed once in a while (whenever it's full, or whenever a newline is printed).

The strange thing is that System.out.println does print when the for loop is running.

The reason for that is that the stream is line-buffered. This means that every newline triggers an implicit flush. The difference between your code and println() is that the latter prints out a newline every time it's called.

NPE
  • 486,780
  • 108
  • 951
  • 1,012
0

Try using Console instead:

for(int i =0; i<5000; i++){
    System.console().format("\b\b\b\b\b\b%2.2f%%", ((float) i/5000f)*100f);
    System.console().flush();
}
Sean Reilly
  • 21,526
  • 4
  • 48
  • 62