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;