Most efficient way to create InputStream from OutputStream Most efficient way to create InputStream from OutputStream java java

Most efficient way to create InputStream from OutputStream


If you don't want to copy all of the data into an in-memory buffer all at once then you're going to have to have your code that uses the OutputStream (the producer) and the code that uses the InputStream (the consumer) either alternate in the same thread, or operate concurrently in two separate threads. Having them operate in the same thread is probably much more complicated that using two separate threads, is much more error prone (you'll need to make sure that the consumer never blocks waiting for input, or you'll effectively deadlock) and would necessitate having the producer and consumer running in the same loop which seems way too tightly coupled.

So use a second thread. It really isn't that complicated. The page you linked to had reasonable example. Here's a somewhat modernized version, which also closes the streams:

try (PipedInputStream in = new PipedInputStream()) {    new Thread(() -> {        try (PipedOutputStream out = new PipedOutputStream(in)) {            writeDataToOutputStream(out);        } catch (IOException iox) {            // handle IOExceptions        }    }).start();    processDataFromInputStream(in);}


There is another Open Source library called EasyStream that deals with pipes and thread in a transparent way. That isn't really complicated if everything goes well. Problems arise when (looking at Laurence Gonsalves example)

class1.putDataOnOutputStream(out);

Throws an exception. In that example the thread simply completes and the exception is lost, while the outer InputStream might be truncated.

Easystream deals with exception propagation and other nasty problems I've been debugging for about one year. (I'm the mantainer of the library: obviously my solution is the best one ;) )Here is an example on how to use it:

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

There is also a nice introduction where all other ways to convert an OutputStream into an InputStream are explained. Worth to have a look.


A simple solution that avoids copying the buffer is to create a special-purpose 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);    }}

Write to the above output stream as needed, then call toInputStream to obtain an input stream over the underlying buffer. Consider the output stream as closed after that point.