我有一个需要读取的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中成为新手而创建了更多问题。
答案 0 :(得分:2)
我最好的猜测是你的parseMetadata
以某种方式关闭了流。我已经尝试了你的方案,它对我来说很好。通常,在处理程序完成读取之前关闭OutputStream
不是问题,这正是管道流的用途。
此外,根据您的情况,我会遗漏管道和附加线程。如果您不介意将整个流存储在内存中,则可以执行类似
的操作ByteArrayOutputStream out = new ByteArrayOutputStream();
fillTheOutput(out);
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
pass1(in);
in.reset();
pass2(in);
如果你介意记忆中的所有内容,那么无论如何你都会遇到麻烦,因为你的BufferedInputStream
大致相同。
编辑:请注意,您可以根据字节数组轻松构建新的ByteArrayInputStream
,这是常规流无法做到的。