Skip to content

Instantly share code, notes, and snippets.

@lovromazgon
Last active March 21, 2016 20:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lovromazgon/9c801554ceb56157de30 to your computer and use it in GitHub Desktop.
Save lovromazgon/9c801554ceb56157de30 to your computer and use it in GitHub Desktop.
A CLI progress bar in Java and InputStream wrapper around the progress bar for ease of use.
package dap.util;
import java.io.PrintStream;
/**
* The CLIProgressBar outputs a progress bar and the time remaining for completing a task.
* <p>
* To use it you must provide the total size / total number of iterations for your task (e.g. file length)
* and update the current position after each iteration.
* <p>
* Example:
* <blockquote><pre>
* File file = new File("path/to/my/file");
*
* CLIProgressBar progressBar = new CLIProgressBar(file.length());
* long readLength = 0;
* BufferedReader data = new BufferedReader(new FileReader(file));
*
* while ((line = data.readLine()) != null) {
* readLength += line.length();
* progressBar.print(readLength);
*
* // do work...
* }
* </pre></blockquote>
* <p>
* Output looks like this:
* <blockquote><pre>
* [=====---------------] (25%, 4min 8s)
* </pre></blockquote>
*
*/
public class CLIProgressBar {
private static final PrintStream DEFAULT_OUT = System.out;
private static final int DEFAULT_SIZE = 20;
private static final boolean DEFAULT_PRINT_TIME_REMAINING = true;
private static final long REFRESH_TIME = 1000; //1 second
private boolean printTimeRemaining;
private long lastTimePrinted;
private long startTimePosition;
private PrintStream out;
private long start;
private long end;
private int progressBarSize;
private long lastPosition;
private long onePercent;
private long startTime;
private String cachedProgressString;
public CLIProgressBar(long end) {
this(end, DEFAULT_SIZE);
}
public CLIProgressBar(long end, int progressBarSize) {
this(0, end, progressBarSize);
}
public CLIProgressBar(long start, long end, int progressBarSize) {
this(start, end, progressBarSize, DEFAULT_PRINT_TIME_REMAINING);
}
public CLIProgressBar(long start, long end, int progressBarSize, boolean printTimeRemaining) {
this(start, end, progressBarSize, printTimeRemaining, DEFAULT_OUT);
}
public CLIProgressBar(long start, long end, int progressBarSize, boolean printTimeRemaining, PrintStream out) {
this.out = out;
this.start = start;
this.end = end;
this.progressBarSize = progressBarSize;
this.lastPosition = start;
this.printTimeRemaining = printTimeRemaining;
updateOnePercent();
}
public PrintStream getOut() {
return out;
}
public void setOut(PrintStream out) {
this.out = out;
}
public long getStart() {
return start;
}
public void setStart(long start) {
this.start = start;
updateOnePercent();
}
public long getEnd() {
return end;
}
public void setEnd(long end) {
this.end = end;
updateOnePercent();
}
public long getOnePercent() {
return onePercent;
}
public int getProgressBarSize() {
return progressBarSize;
}
public void setProgressBarSize(int progressBarSize) {
this.progressBarSize = progressBarSize;
}
private void updateOnePercent() {
this.onePercent = (end-start)/100;
}
public void reset() {
lastPosition = start;
startTimePosition = 0;
}
public void print(long currentPosition) {
print(currentPosition, false);
}
public void print(long currentPosition, boolean permanent) {
if (currentPosition >= lastPosition + onePercent || lastPosition == start) {
lastPosition = currentPosition;
double percent = Math.round((100 * (currentPosition - start)) / (end - start)) / 100.0;
StringBuilder sb = new StringBuilder();
if (!permanent) {
sb.append("\r");
}
sb.append("[");
int currentBarSize = (int)Math.round(progressBarSize*percent);
for (int i = 0; i < currentBarSize; i++) {
sb.append("=");
}
for (int i = 0; i < progressBarSize - currentBarSize; i++) {
sb.append("-");
}
sb.append("] (");
sb.append((int)(percent*100));
sb.append("%");
cachedProgressString = sb.toString();
} else if (!printTimeRemaining || System.currentTimeMillis() - lastTimePrinted < REFRESH_TIME) {
return;
}
out.print(cachedProgressString + createTimeString(currentPosition) + ")");
if (permanent || currentPosition == end) {
out.println();
}
lastTimePrinted = System.currentTimeMillis();
}
private String createTimeString(long currentPosition) {
if (!printTimeRemaining) {
return "";
} else if (startTimePosition == 0) {
startTime = System.currentTimeMillis();
startTimePosition = currentPosition;
return " ...";
}
long elapsed = System.currentTimeMillis() - startTime;
long remaining = (long)(((double)elapsed) * (end-currentPosition) / (currentPosition-startTimePosition));
String hours = extractHours(remaining);
String minutes = extractMinutes(remaining);
String seconds = extractSeconds(remaining);
StringBuilder sb = new StringBuilder(" ");
if (!hours.isEmpty()) {
sb.append(hours);
}
if (!minutes.isEmpty()) {
if (sb.length() > 1) sb.append(" ");
sb.append(minutes);
}
if (hours.isEmpty()) {
if (sb.length() > 1) sb.append(" ");
sb.append(seconds);
}
return sb.toString();
}
private String extractHours(long time) {
long hours = time / 3_600_000;
if (hours != 0) {
return hours + "h";
} else {
return "";
}
}
private String extractMinutes(long time) {
long minutes = (time / 60_000) % 60;
if (minutes != 0) {
return minutes + "min";
} else {
return "";
}
}
private String extractSeconds(long time) {
long seconds = (time / 1000) % 60;
return seconds + "s";
}
}
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* The ProgressBarInputStream outputs a progress bar while reading the InputStream.
* <p>
* Example:
* <blockquote><pre>
* File file = new File("path/to/my/file");
* BufferedInputStream data = new BufferedInputStream(new ProgressBarInputStream(new FileInputStream(file)));
*
* // do work...
*
* data.close()
* </pre></blockquote>
* <p>
* Output looks like this:
* <blockquote><pre>
* [=====---------------] (25%)
* </pre></blockquote>
*
*/
public class ProgressBarInputStream extends FilterInputStream {
private CLIProgressBar progressBar;
private int nread = 0;
private int size = 0;
public ProgressBarInputStream(InputStream in) {
super(in);
try {
size = in.available();
}
catch(IOException ioe) {
size = 0;
}
progressBar = new CLIProgressBar(size);
}
public CLIProgressBar getProgressBar() {
return progressBar;
}
@Override
public int read() throws IOException {
int c = in.read();
if (c >= 0) progressBar.print(++nread);
return c;
}
@Override
public int read(byte[] b) throws IOException {
int nr = in.read(b);
if (nr > 0) progressBar.print(nread += nr);
return nr;
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
int nr = in.read(b, off, len);
if (nr > 0) progressBar.print(nread += nr);
return nr;
}
@Override
public long skip(long n) throws IOException {
long nr = in.skip(n);
if (nr > 0) progressBar.print(nread += nr);
return nr;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment