从OutputStream创建InputStream的最有效方法

[英]Most efficient way to create InputStream from OutputStream


This page: http://blog.ostermiller.org/convert-java-outputstream-inputstream describes how to create an InputStream from OutputStream:

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

new ByteArrayInputStream(out.toByteArray())

Other alternatives are to use PipedStreams and new threads which is cumbersome.

其他的替代方法是使用管道流和新线程,这很麻烦。

I do not like the idea of copying many megabytes to new in memory byte array. Is there a library that does this more efficiently?

我不喜欢将许多兆字节复制到新的内存字节数组中。有图书馆能更有效地做到这一点吗?

EDIT:

编辑:

By advice from Laurence Gonsalves, i tried PipedStreams and it turned out they are not that hard to deal with. Here's the sample code in clojure:

根据劳伦斯·冈萨弗斯的建议,我尝试了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))

5 个解决方案

#1


64  

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.

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

So use a second thread. It really isn't that complicated. The page you linked to had a perfect example:

所以用第二条线。其实也没那么复杂。你链接的页面有一个完美的例子:

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

#2


15  

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)

还有一个名为EasyStream的开源库,它以透明的方式处理管道和线程。如果一切顺利的话,这并不复杂。当(看劳伦斯·冈萨维斯的例子)时出现了问题

class1.putDataOnOutputStream(out);

class1.putDataOnOutputStream(出);

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

将抛出一个异常。在这个示例中,线程只会完成并丢失异常,而外部InputStream可能会被截断。

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:

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

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

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

#3


8  

A simple solution that avoids copying the buffer is to create a special-purpose ByteArrayOutputStream:

避免复制缓冲区的一个简单解决方案是创建一个特殊用途的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.

根据需要写入上面的输出流,然后调用toInputStream来获得底层缓冲区上的输入流。考虑输出流在那个点之后是关闭的。

#4


5  

I think the best way to connect InputStream to an OutputStream is through piped streams - available in java.io package, as follow:

我认为将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.*/

In my opinion there are two main advantages for this code:

在我看来,该代码有两个主要优点:

1 - There is no additional consumption of memory except for the buffer.

1 -除了缓冲区之外,没有额外的内存消耗。

2 - You don't need to handle data queuing manually

2 -您不需要手动处理数据排队

#5


0  

I usually try to avoid creating a separate thread because of the increased chance of deadlock, the increased difficulty of understanding the code, and the problems of dealing with exceptions.

我通常尽量避免创建单独的线程,因为死锁的可能性增加,理解代码的难度增加,以及处理异常的问题。

Here's my proposed solution: a ProducerInputStream that creates content in chunks by repeated calls to produceChunk():

下面是我的建议解决方案:一个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);

}
智能推荐

注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:http://www.itdaan.com/blog/2009/08/04/d8d8fcb823b9a8a4923abb783c920669.html



 
© 2014-2019 ITdaan.com 粤ICP备14056181号  

赞助商广告