从OutputStream创buildInputStream的最有效的方法

本页面: http : //blog.ostermiller.org/convert-java-outputstream-inputstream描述如何从OutputStream创build一个InputStream:

new ByteArrayInputStream(out.toByteArray()) 

其他的select是使用PipedStreams和新的线程,这是很麻烦的。

我不喜欢将很多兆字节复制到内存中的新字节数组的想法。 有没有更高效的图书馆?

编辑:

从Laurence Gonsalves的build议,我尝试了PipedStreams,事实certificate他们并不难处理。 以下是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)) 

如果你不想将所有的数据一次全部复制到内存中,那么你将不得不使用OutputStream(生产者)和使用InputStream(消费者)或者在同一个线程中交替,或者在两个单独的线程中同时运行。 让它们在同一个线程中运行可能要复杂得多,因为使用两个单独的线程更容易出错(您需要确保消费者永远不会阻塞等待input,否则会导致死锁),并且必须让生产者和消费者在相同的循环中运行,看起来过于紧密。

所以使用第二个线程。 这真的不是那么复杂。 您链接的页面有一个完美的例子:

  PipedInputStream in = new PipedInputStream(); PipedOutputStream out = new PipedOutputStream(in); new Thread( new Runnable(){ public void run(){ class1.putDataOnOutputStream(out); } } ).start(); class2.processDataFromInputStream(in); 

还有另一个名为EasyStream的开源库,它以透明的方式处理pipe道和线程。 如果一切顺利,这并不复杂。 出现问题时(以Laurence Gonsalves为例)

class1.putDataOnOutputStream(下);

引发exception。 在这个例子中,线程简单地完成,exception丢失,而外部InputStream可能被截断。

Easystream处理exception传播和我已经debugging了大约一年的其他讨厌的问题。 (我是图书馆的mantainer:显然我的解决scheme是最好的;))下面是一个如何使用它的例子:

 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) } }; 

还有一个很好的介绍 ,其中介绍了将OutputStream转换为InputStream的所有其他方法。 值得一看。

我认为将InputStream连接到OutputStream的最好方法是通过pipe道stream (在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 – 您不需要手动处理数据排队

避免复制缓冲区的简单解决scheme是创build一个特殊用途的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); } } 

根据需要写入上面的输出stream,然后调用toInputStream以获取基础缓冲区上的inputstream。 考虑输出stream在那之后closures。

我通常会尝试避免创build一个单独的线程,因为死锁的机会增加,理解代码的难度增加,以及处理exception的问题。

这里是我提出的解决scheme:一个ProducerInputStream,通过反复调用produceChunk()来创build块的内容:

 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); }