带有rewind()/ reset()功能的java文件输入

时间:2009-07-07 20:32:41

标签: java io stream

我需要编写一个函数,它接受某种输入流的东西(例如一个InputStream或一个FileChannel),以便在两次传递中读取一个大文件:一次预先计算一些容量,第二次执行“真正的” “工作。我不希望一次将整个文件加载到内存中(除非它很小)。

是否有适当的Java类提供此功能? FileInputStream本身不支持mark()/ reset()。我认为BufferedInputStream确实如此,但我不清楚是否必须存储整个文件来执行此操作。

C非常简单,只需使用fseek(),ftell()和rewind()即可。 : - (

9 个答案:

答案 0 :(得分:25)

我认为引用FileChannel的答案已经出现了。

以下是封装此功能的输入流的示例实现。它使用委托,因此它不是真正的FileInputStream,但它是一个InputStream,通常就足够了。如果这是一个要求,可以类似地扩展FileInputStream。

未经测试,使用风险自负:)

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);
    }
}

答案 1 :(得分:22)

BufferedInputStream通过缓冲内存中的内容来支持mark。它最好保留用于可预测大小的相对较小的预测。

相反,RandomAccessFile可以直接使用,也可以作为具体InputStream的基础,并使用rewind()方法进行扩展。

或者,可以为每个传递打开一个新的FileInputStream

答案 2 :(得分:19)

如果从FileChannel获得关联的FileInputStream,则可以使用position方法将文件指针设置为文件中的任何位置。

FileInputStream fis = new FileInputStream("/etc/hosts");
FileChannel     fc = fis.getChannel();


fc.position(100);// set the file pointer to byte position 100;

答案 3 :(得分:7)

java.nio.channels.FileChannel有一个方法position(long)可以将位置重置为零,就像C中的fseek()一样。

答案 4 :(得分:6)

RandomAccessFile就是你想要的:

答案 5 :(得分:2)

查看java.io.RandomAccessFile

答案 6 :(得分:2)

PushbackInputStream也可以工作,只要你知道你想要倒回多少个字符

答案 7 :(得分:2)

BufferedInputStreammark(readlimit)reset()readlimit应大于filesize以使商标有效。 file.length()+1没问题。 这意味着标记在读取readlimit字节之前有效,因此您可以返回reset()

答案 8 :(得分:2)

你想要的是RandomAccessFileInputStream - 使用mark / reset实现InputStream接口,有时基于RandomAccessFiles进行搜索。存在一些可能满足您需要的实现。

完整源代码的一个示例是http://www.fuin.org/utils4j/index.html,但你会发现许多其他人在互联网上搜索,如果没有完全适合的话,它很容易编码。