如何将 InputStream 用于 RandomAccessFile 的一部分?

How can I use an InputStream for parts of a RandomAccessFile?

我是 Java 的新手,我编写了一个适用于 RandomAccessFile 的解析器(文件格式需要随机定位)。对于 JUnit 测试,我将不同的示例输入文件提供给解析器。

现在我认为在将解析器更改为从 InputStream 中读取(这将由 JUnit 测试创建)后,我可以编写更简单的 JUnit 测试。

但是为了能够执行非测试用例,我必须创建(或更新)一个 InputStream 来读取 RandomAccessFile 当前指向的位置。 这可能吗?当然,解决方案应该兼顾高效和优雅。

没有比这更聪明的主意了,这就是我所做的。不幸的是,构造函数的非常有限的性质和 super() 的使用以及 Java 中缺少多重继承使得实现比必要的更难和更丑陋。 BufferedInputStream 的缓冲区缺少受保护的 invalidate() 让我猜测如何去做(测试表明它有效):

package de.whatever.uw.utils;

import java.io.BufferedInputStream;

/**
 * @author U. Windl
 */
public class RandomAccessFileInputStream extends BufferedInputStream {

    private RandomAccessFile file;  // file to use

   /**
     * Constructor
     * @param fileName File to open for reading
     * @throws FileNotFoundException 
     */
    public RandomAccessFileInputStream(String fileName) throws FileNotFoundException {
        super(System.in);   // dummy to work around Java's inflexibility
        assert fileName != null;
        file = new RandomAccessFile(fileName, "r");
        FileChannel channel = file.getChannel();
        in = new BufferedInputStream(Channels.newInputStream(channel));
        assert file != null;
    }

    /**
     * Forbidden Constructor
     * @param in Input stream
     */
    private RandomAccessFileInputStream(InputStream in) {
        super(in);
    }

    /**
     * Forbidden Constructor
     * @param in
     * @param size
     */
    private RandomAccessFileInputStream(InputStream in, int size) {
        super(in, size);
    }

    /* (non-Javadoc)
     * @see java.io.BufferedInputStream#close()
     */
    public void close() throws IOException {
        super.close();
        file.close();
    }

    /**
     * @return Current offset in stream
     * @throws IOException
     */
    public long getFilePointer() throws IOException {
        return file.getFilePointer();
    }

    /**
     * @return
     * @throws IOException
     * @see java.io.RandomAccessFile#length()
     */
    public long length() throws IOException {
        return file.length();
    }

    /**
     * @param pos New stream position
     * @throws IOException
     */
    public void seek(long pos) throws IOException {
        file.seek(pos);
        pos = count = 0;    // invalidate stream buffer
    }

    // other methods are inherited without change (and I really use a very few of them actually)
}

(我已经创建了一个大约 8kB 大小的特殊测试文件来测试定位和缓冲:位置更改后读取正确的数据(使缓冲区无效似乎有效),并且读取的数据超过请求的大小(即缓冲也有效。)