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);
}
Author by
Tom Marthenal
Updated on July 09, 2022Comments
-
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 over 13 yearsBut 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 about 6 yearsI used
\r
, but it is acting like\n
. I am usingprint
instead ofprintln
. Any idea why it's not working? -
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 about 6 years@newsha ah, that seems to be the case. Thank you!
-
PhDeveloper over 5 yearsI 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 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 almost 5 yearsI had quite huge values (bytewise file upload) so instead of the
int percent = (int) (current * 100 / total);
I had to useint percent = (int) (((float)current / (float)total) * 100);
in order to avoid integer overflow. -
Saurav Kumar over 4 yearsDoes it depend on size of terminal window??
-
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 about 2 yearsIf 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!