[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