如何缓存输入流以供多用途

2022-09-01 08:40:08

我有一个文件的InputStream,我使用apache poi组件从中读取,如下所示:

POIFSFileSystem fileSystem = new POIFSFileSystem(inputStream);

问题是我需要多次使用相同的流,并且POIFSFileSystem在使用后关闭流。

缓存输入流中的数据,然后将更多输入流提供给不同的POIFSFileSystem的最佳方法是什么?

编辑1:

通过缓存,我的意思是存储供以后使用,而不是作为加速应用程序的方法。另外,将输入流读取到数组或字符串中,然后为每次使用创建输入流是否更好?

编辑2:

很抱歉重新打开这个问题,但是在桌面和Web应用程序中工作时,条件有些不同。首先,我从tomcat web应用程序中的org.apache.commons.fileupload.FileItem获得的InputStream不支持标记,因此无法重置。

其次,我希望能够将文件保存在内存中,以便在处理文件时更快地访问并减少io问题。


答案 1

你可以用一个版本来修饰传递给POIFSFileSystem的输入流,当调用close()时,它会用reset()响应:

class ResetOnCloseInputStream extends InputStream {

    private final InputStream decorated;

    public ResetOnCloseInputStream(InputStream anInputStream) {
        if (!anInputStream.markSupported()) {
            throw new IllegalArgumentException("marking not supported");
        }

        anInputStream.mark( 1 << 24); // magic constant: BEWARE
        decorated = anInputStream;
    }

    @Override
    public void close() throws IOException {
        decorated.reset();
    }

    @Override
    public int read() throws IOException {
        return decorated.read();
    }
}

测试用例

static void closeAfterInputStreamIsConsumed(InputStream is)
        throws IOException {
    int r;

    while ((r = is.read()) != -1) {
        System.out.println(r);
    }

    is.close();
    System.out.println("=========");

}

public static void main(String[] args) throws IOException {
    InputStream is = new ByteArrayInputStream("sample".getBytes());
    ResetOnCloseInputStream decoratedIs = new ResetOnCloseInputStream(is);
    closeAfterInputStreamIsConsumed(decoratedIs);
    closeAfterInputStreamIsConsumed(decoratedIs);
    closeAfterInputStreamIsConsumed(is);
}

编辑 2

您可以在byte[](slurp模式)中读取整个文件,然后将其传递到ByteArrayInputStream


答案 2

尝试BufferedInputStream,它将标记和重置功能添加到另一个输入流,并仅覆盖其关闭方法:

public class UnclosableBufferedInputStream extends BufferedInputStream {

    public UnclosableBufferedInputStream(InputStream in) {
        super(in);
        super.mark(Integer.MAX_VALUE);
    }

    @Override
    public void close() throws IOException {
        super.reset();
    }
}

所以:

UnclosableBufferedInputStream  bis = new UnclosableBufferedInputStream (inputStream);

并在以前使用过 inputStream 的任何地方使用。bis