最有效的方式,从创建的OutputStream的InputStream(Most efficient

2019-06-18 00:02发布

本页面: 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))

Answer 1:

如果你不希望所有的数据复制到内存缓冲区一下子那么你将必须有你的代码,使用的OutputStream(生产者)和使用InputStream的代码(消费者)或者替代在同一个线程,或者在两个单独的线程同时工作。 让他们在同一个线程操作可能要复杂得多,使用两个独立的线程,是更容易出错(你需要确保消费者不会阻塞等待输入,否则你会有效死锁)和将需要具有相同的循环,这似乎太紧密耦合的生产者和消费者的运行。

因此,使用第二个线程。 这真的不是那么复杂。 您链接到页面有一个很好的例子:

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


Answer 2:

还有一种叫开源库EasyStream与以透明的方式管和线交易。 如果一切顺利的话是不是真的很复杂。 出现问题时(看劳伦斯·贡萨尔维斯例子)

class1.putDataOnOutputStream(下);

抛出异常。 在那个例子中的线程简单地完成和异常丢失,而外部InputStream可能会被截断。

与异常的传播和其他令人讨厌的问题Easystream交易我已经调试了一年左右。 (我是图书馆的mantainer:显然,我的解决方案是最好的;))下面是关于如何使用它的一个示例:

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解释。 值得看看。



Answer 3:

这避免了复制缓冲区的简单解决方案是创建一个特殊目的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在基础缓冲区获得的输入流。 考虑输出流点后为关闭。



Answer 4:

我认为的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 - 你并不需要处理的数据手动排队



Answer 5:

我通常会尽量避免,因为死锁的几率就越大,理解代码的难度增加,以及处理异常的问题创建一个单独的线程。

这是我提出的解决方案:通过重复调用produceChunk()创建块内容ProducerInputStream:

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

}


文章来源: Most efficient way to create InputStream from OutputStream