此页面:http://blog.ostermiller.org/convert-java-outputstream-inputstream 介绍如何从OutputStream创建InputStream:
new ByteArrayInputStream(out.toByteArray())
其他替代方法是使用PipedStreams和新线程,这很麻烦。
我不喜欢将许多兆字节复制到内存字节数组中的新内容。 有没有一个库可以更有效地完成这项工作?
编辑:
根据劳伦斯贡萨尔维斯的建议,我尝试了PipedStreams,事实证明他们并没有那么难对付。 这是clojure中的示例代码:
(defn #^PipedInputStream create-pdf-stream [pdf-info]
(let [in-stream (new PipedInputStream)
out-stream (PipedOutputStream. in-stream)]
(.start (Thread. #(;Here you write into out-stream)))
in-stream))
答案 0 :(得分:66)
如果您不想一次性将所有数据复制到内存缓冲区中,那么您将不得不使用使用OutputStream(生产者)的代码和使用InputStream的代码。 (消费者)要么在同一个线程中交替,要么在两个单独的线程中同时操作。让它们在同一个线程中运行可能要复杂得多,使用两个独立的线程,更容易出错(你需要确保消费者从不阻止等待输入,或者你' ll有效死锁)并且必须让生产者和消费者在相同的循环中运行,这似乎过于紧密耦合。
所以使用第二个线程。这真的不是那么复杂。您链接的页面有一个完美的例子:
PipedInputStream in = new PipedInputStream();
PipedOutputStream out = new PipedOutputStream(in);
new Thread(
new Runnable(){
public void run(){
class1.putDataOnOutputStream(out);
}
}
).start();
class2.processDataFromInputStream(in);
答案 1 :(得分:15)
还有另一个名为 EasyStream 的开源库,它以透明的方式处理管道和线程。 如果一切顺利,这并不是很复杂。当(看Laurence Gonsalves的例子)
时会出现问题class1.putDataOnOutputStream(下);
引发异常。
在该示例中,线程完成并且异常丢失,而外部InputStream
可能被截断。
Easystream处理异常传播和其他令人讨厌的问题,我已经调试了大约一年。 (我是图书馆的傻瓜:显然我的解决方案是最好的;)) 以下是如何使用它的示例:
final InputStreamFromOutputStream<String> isos = new InputStreamFromOutputStream<String>(){
@Override
public String produce(final OutputStream dataSink) throws Exception {
/*
* call your application function who produces the data here
* WARNING: we're in another thread here, so this method shouldn't
* write any class field or make assumptions on the state of the outer class.
*/
return produceMydata(dataSink)
}
};
还有一个很好的introduction,其中解释了将OutputStream转换为InputStream的所有其他方法。值得一看。
答案 2 :(得分:9)
避免复制缓冲区的简单解决方案是创建一个专用的ByteArrayOutputStream
:
public class CopyStream extends ByteArrayOutputStream {
public CopyStream(int size) { super(size); }
/**
* Get an input stream based on the contents of this output stream.
* Do not use the output stream after calling this method.
* @return an {@link InputStream}
*/
public InputStream toInputStream() {
return new ByteArrayInputStream(this.buf, 0, this.count);
}
}
根据需要写入上面的输出流,然后调用toInputStream
以获取基础缓冲区上的输入流。在该点之后将输出流视为已关闭。
答案 3 :(得分:6)
我认为将InputStream连接到OutputStream的最佳方法是通过管道流 - 在java.io包中提供,如下所示:
// 1- Define stream buffer
private static final int PIPE_BUFFER = 2048;
// 2 -Create PipedInputStream with the buffer
public PipedInputStream inPipe = new PipedInputStream(PIPE_BUFFER);
// 3 -Create PipedOutputStream and bound it to the PipedInputStream object
public PipedOutputStream outPipe = new PipedOutputStream(inPipe);
// 4- PipedOutputStream is an OutputStream, So you can write data to it
// in any way suitable to your data. for example:
while (Condition) {
outPipe.write(mByte);
}
/*Congratulations:D. Step 4 will write data to the PipedOutputStream
which is bound to the PipedInputStream so after filling the buffer
this data is available in the inPipe Object. Start reading it to
clear the buffer to be filled again by the PipedInputStream object.*/
在我看来,这个代码有两个主要优点:
1 - 除缓冲区外没有额外的内存消耗。
2 - 您不需要手动处理数据排队
答案 4 :(得分:1)
我经常试图避免创建一个单独的线程,因为死锁的可能性增加,理解代码的难度增加,以及处理异常的问题。
这是我提出的解决方案:一个ProducerInputStream,通过重复调用produceChunk()创建内容:
public abstract class ProducerInputStream extends InputStream {
private ByteArrayInputStream bin = new ByteArrayInputStream(new byte[0]);
private ByteArrayOutputStream bout = new ByteArrayOutputStream();
@Override
public int read() throws IOException {
int result = bin.read();
while ((result == -1) && newChunk()) {
result = bin.read();
}
return result;
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
int result = bin.read(b, off, len);
while ((result == -1) && newChunk()) {
result = bin.read(b, off, len);
}
return result;
}
private boolean newChunk() {
bout.reset();
produceChunk(bout);
bin = new ByteArrayInputStream(bout.toByteArray());
return (bout.size() > 0);
}
public abstract void produceChunk(OutputStream out);
}