java – 使用BufferedInputStream包装PipedInputStream

我有一个需要读取的OutputStream,因此我使用以下(Groovy)代码来获取对数据的InputStream引用:

PipedInputStream inputStream = new PipedInputStream()
    PipedOutputStream outputStream = new PipedOutputStream(inputStream)
    new Thread(
            new Runnable() {
                public void run() {
                    // Some API method
                    putDataInOutputStream(outputStream)
                    outputStream.close()
                }
            }
    ).start()

handler.process(inputStream)

在这种情况下,handler是一个实现具有此方法的接口的类:

public void process(InputStream stream);

我们的新要求中出现的问题是流上有一些预处理,因此我需要在handler.process()方法中至少读取两次流.以下是一个实现的一些示例代码:

public void process(InputStream stream) {
    def bufferedStream = new BufferedInputStream(stream, 30 * 1048576)  // 30 MB
    bufferedStream.mark(Integer.MAX_VALUE)
    parseMetadata(bufferedStream)
    bufferedStream.reset()
    doTheThingYouDo(bufferedStream)
 }

我知道对于某些输入我没有达到30 MB的限制或Integer.MAX_VALUE缓冲区大小.但是,我总是得到以下异常:

java.io.IOException: Stream closed

这甚至可能吗?我认为问题是关闭PipedOutputStream的线程,但我不知道如何防止这种情况,或者我是否因为在Java Stream IO中成为新手而创建了更多问题.

最佳答案 我最好的猜测是你的parseMetadata以某种方式关闭了流.我已经尝试了你的方案,它对我来说很好.通常,在处理程序完成读取之前关闭OutputStream不是问题,这正是管道流的用途.

此外,根据您的情况,我会省略管道和附加线程.如果您不介意将整个流存储在内存中,您可以执行类似的操作

ByteArrayOutputStream out = new ByteArrayOutputStream();

fillTheOutput(out);

ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());

pass1(in);
in.reset();
pass2(in);

如果你介意在内存中拥有所有内容,那么无论如何你都会遇到麻烦,因为你的BufferedInputStream大致相同.

编辑:请注意,您可以根据字节数组轻松构建新的ByteArrayInputStream,这是常规流无法做到的.

点赞