I need to write a function that takes in some kind of input stream thing (e.g. an InputStream or a FileChannel) in order to read a large file in two passes: once to precompu
What you want is RandomAccessFileInputStream
- implements InputStream
interface with mark/reset, sometimes seek based on RandomAccessFiles
. Some implementations exist which might do what you need.
One example complete with sources is in http://www.fuin.org/utils4j/index.html but you would find many others searching the internet and its is easy enough to code if none fits exactly.
Check out java.io.RandomAccessFile
I think the answers referencing a FileChannel are on the mark .
Here's a sample implementation of an input stream that encapsulates this functionality. It uses delegation, so it's not a true FileInputStream, but it is an InputStream, which is usually sufficient. One could similarly extend FileInputStream if that's a requirement.
Not tested, use at your own risk :)
public class MarkableFileInputStream extends FilterInputStream {
private FileChannel myFileChannel;
private long mark = -1;
public MarkableFileInputStream(FileInputStream fis) {
super(fis);
myFileChannel = fis.getChannel();
}
@Override
public boolean markSupported() {
return true;
}
@Override
public synchronized void mark(int readlimit) {
try {
mark = myFileChannel.position();
} catch (IOException ex) {
mark = -1;
}
}
@Override
public synchronized void reset() throws IOException {
if (mark == -1) {
throw new IOException("not marked");
}
myFileChannel.position(mark);
}
}
java.nio.channels.FileChannel
has a method position(long)
to reset the position back to zero like fseek() in C.
BufferedInputStream
supports mark
by buffering the content in memory. It is best reserved for relatively small look-aheads of a predictable size.
Instead, RandomAccessFile
can be used directly, or it could serve as the basis for a concrete InputStream
, extended with a rewind()
method.
Alternatively, a new FileInputStream
can be opened for each pass.
If you get the associated FileChannel
from the FileInputStream
, you can use the position method to set the file pointer to anywhere in the file.
FileInputStream fis = new FileInputStream("/etc/hosts");
FileChannel fc = fis.getChannel();
fc.position(100);// set the file pointer to byte position 100;