[New] added FileProgressListener with ProgressableFileInputStream

This commit is contained in:
Robert von Burg 2014-02-02 20:42:27 +01:00
parent a8264aca37
commit 09444817e2
4 changed files with 311 additions and 0 deletions

View File

@ -0,0 +1,41 @@
package ch.eitchnet.utils.io;
/**
* <p>
* This interface defines an API for use in situations where long running jobs notify observers of the jobs status. The
* jobs has a size which is a primitive long value e.g. the number of bytes parsed/ to be parsed in a file
* </p>
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public interface FileProgressListener {
/**
* Notify the listener that the progress has begun
*
* @param size
* the size of the job which is to be accomplished
*/
public void begin(long size);
/**
* Notifies the listener of incremental progress
*
* @param percent
* percent completed
* @param position
* the position relative to the job size
*/
public void progress(int percent, long position);
/**
* Notifies the listener that the progress is completed
*
* @param percent
* the percent completed. Ideally the value would be 100, but in cases of errors it can be less
* @param position
* the position where the job finished. Ideally the value would be the same as the size given at
* {@link #begin(long)} but in case of errors it can be different
*/
public void end(int percent, long position);
}

View File

@ -0,0 +1,81 @@
package ch.eitchnet.utils.io;
import java.text.MessageFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* File stream progress monitoring thread
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public class FileStreamProgressWatcher implements Runnable {
private static final Logger logger = LoggerFactory.getLogger(FileStreamProgressWatcher.class);
private ProgressableFileInputStream inputStream;
private boolean run = false;
private FileProgressListener progressListener;
private long millis;
/**
* @param millis
* @param progressListener
* @param inputStream
*/
public FileStreamProgressWatcher(long millis, FileProgressListener progressListener,
ProgressableFileInputStream inputStream) {
this.millis = millis;
this.progressListener = progressListener;
this.inputStream = inputStream;
}
@Override
public void run() {
this.run = true;
this.progressListener.begin(this.inputStream.getFileSize());
while (this.run) {
try {
int percentComplete = this.inputStream.getPercentComplete();
if (this.inputStream.isClosed()) {
logger.info(MessageFormat.format("Input Stream is closed at: {0}%", percentComplete)); //$NON-NLS-1$
this.run = false;
this.progressListener.end(percentComplete, this.inputStream.getBytesRead());
} else if (percentComplete < 100) {
this.progressListener.progress(percentComplete, this.inputStream.getBytesRead());
} else if (percentComplete >= 100) {
this.run = false;
this.progressListener.end(percentComplete, this.inputStream.getBytesRead());
}
if (this.run) {
Thread.sleep(this.millis);
}
} catch (InterruptedException e) {
logger.info(MessageFormat.format("Work stopped: {0}", e.getLocalizedMessage())); //$NON-NLS-1$
this.run = false;
int percentComplete = this.inputStream.getPercentComplete();
this.progressListener.end(percentComplete, this.inputStream.getBytesRead());
} catch (Exception e) {
logger.error(e.getMessage(), e);
this.run = false;
int percentComplete = this.inputStream.getPercentComplete();
this.progressListener.end(percentComplete, Long.MAX_VALUE);
}
}
}
}

View File

@ -0,0 +1,43 @@
package ch.eitchnet.utils.io;
import java.text.MessageFormat;
import org.slf4j.Logger;
import ch.eitchnet.utils.helper.FileHelper;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public class LoggingFileProgressListener implements FileProgressListener {
private final Logger logger;
private final String name;
/**
* @param logger
* @param name
*/
public LoggingFileProgressListener(Logger logger, String name) {
this.logger = logger;
this.name = name;
}
@Override
public void begin(long size) {
String msg = "Starting to read {0} with a size of {1}"; //$NON-NLS-1$
this.logger.info(MessageFormat.format(msg, this.name, FileHelper.humanizeFileSize(size)));
}
@Override
public void progress(int percent, long position) {
String msg = "Read {0}% of {1} at position {2}"; //$NON-NLS-1$
this.logger.info(MessageFormat.format(msg, percent, this.name, FileHelper.humanizeFileSize(position)));
}
@Override
public void end(int percent, long position) {
String msg = "Finished reading {0} at position {1} ({2}%)"; //$NON-NLS-1$
this.logger.info(MessageFormat.format(msg, this.name, percent, FileHelper.humanizeFileSize(position)));
}
}

View File

@ -0,0 +1,146 @@
package ch.eitchnet.utils.io;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
/**
* <p>
* This sub class of {@link FileInputStream} allows to follow the currently read bytes of a {@link File}. In conjunction
* with a {@link Thread} and a {@link FileProgressListener} it is possible to track the progress of a long running job on
* bigger files
* </p>
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public class ProgressableFileInputStream extends FileInputStream {
private long fileSize;
private long bytesRead;
private boolean closed;
/**
* Constructs a normal {@link FileInputStream} with the given {@link File}
*
* @param file
* the file to read
* @throws FileNotFoundException
* thrown if the {@link File} does not exist
*/
public ProgressableFileInputStream(File file) throws FileNotFoundException {
super(file);
this.fileSize = file.length();
}
/**
* @see java.io.FileInputStream#read()
*/
@Override
public int read() throws IOException {
synchronized (this) {
this.bytesRead++;
}
return super.read();
}
/**
* @see java.io.FileInputStream#read(byte[], int, int)
*/
@Override
public int read(byte[] b, int off, int len) throws IOException {
int read = super.read(b, off, len);
if (read != -1) {
synchronized (this) {
this.bytesRead += read;
}
}
return read;
}
/**
* @see java.io.FileInputStream#read(byte[])
*/
@Override
public int read(byte[] b) throws IOException {
int read = super.read(b);
if (read != -1) {
synchronized (this) {
this.bytesRead += read;
}
}
return read;
}
/**
* @see java.io.FileInputStream#skip(long)
*/
@Override
public long skip(long n) throws IOException {
long skip = super.skip(n);
if (skip != -1) {
synchronized (this) {
this.bytesRead += skip;
}
}
return skip;
}
/**
* @see java.io.FileInputStream#close()
*/
@Override
public void close() throws IOException {
this.closed = true;
super.close();
}
/**
* Returns the size of the file being read
*
* @return the size of the file being read
*/
public long getFileSize() {
return this.fileSize;
}
/**
* Returns the number of bytes already read
*
* @return the number of bytes already read
*/
public long getBytesRead() {
synchronized (this) {
if (this.bytesRead > this.fileSize)
this.bytesRead = this.fileSize;
return this.bytesRead;
}
}
/**
* Returns the percent read of the file
*
* @return the percentage complete of the process
*/
public int getPercentComplete() {
long currentRead;
synchronized (this) {
if (this.bytesRead > this.fileSize)
this.bytesRead = this.fileSize;
currentRead = this.bytesRead;
}
double read = (100.0d / this.fileSize * currentRead);
return (int) read;
}
/**
* Returns true if {@link #close()} was called, false otherwise
*
* @return the closed
*/
public boolean isClosed() {
return this.closed;
}
}