Last active
March 21, 2016 20:54
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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