[New] added FileProgressListener with ProgressableFileInputStream
This commit is contained in:
parent
a8264aca37
commit
09444817e2
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)));
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue