如何缓存InputStream以供多种用途

Azd*_*der 25 java caching inputstream apache-poi

我有一个文件的InputStream,我使用apache poi组件来读取它像这样:

POIFSFileSystem fileSystem = new POIFSFileSystem(inputStream);
Run Code Online (Sandbox Code Playgroud)

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

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

编辑1:

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

编辑2:

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

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

Tom*_*asz 20

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

public class UnclosableBufferedInputStream extends BufferedInputStream {

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

    @Override
    public void close() throws IOException {
        super.reset();
    }
}
Run Code Online (Sandbox Code Playgroud)

所以:

UnclosableBufferedInputStream  bis = new UnclosableBufferedInputStream (inputStream);
Run Code Online (Sandbox Code Playgroud)

并使用bis之前使用过inputStream的地方.

  • 您的InputStream是否支持它并不重要.BufferedInputStream包装另一个流,缓冲输入,并支持自己标记.被覆盖的关闭方法,无论何时消耗,都可以方便地重置它. (2认同)

dfa*_*dfa 18

您可以使用一个版本来装饰传递给POIFSFileSystem的 InputStream ,当调用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();
    }
}
Run Code Online (Sandbox Code Playgroud)

测试用例

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);
}
Run Code Online (Sandbox Code Playgroud)

编辑2

你可以用byte [](slurp模式)读取整个文件,然后将它传递给ByteArrayInputStream

  • 我只是把Integer.MAX_VALUE,无论如何,谢谢它就像一个魅力. (3认同)

小智 5

这可以正常工作:

byte[] bytes = getBytes(inputStream);
POIFSFileSystem fileSystem = new POIFSFileSystem(new ByteArrayInputStream(bytes));
Run Code Online (Sandbox Code Playgroud)

getBytes是这样的:

private static byte[] getBytes(InputStream is) throws IOException {
    byte[] buffer = new byte[8192];
ByteArrayOutputStream baos = new ByteArrayOutputStream(2048);
int n;
baos.reset();

while ((n = is.read(buffer, 0, buffer.length)) != -1) {
      baos.write(buffer, 0, n);
    }

   return baos.toByteArray();
 }
Run Code Online (Sandbox Code Playgroud)