如何将OutputStream转换为InputStream?

我处于开发阶段,我有两个模块,从一个OutputStream输出,另一个只接受InputStream 。 你知道如何将OutputStream转换为InputStream (反之亦然,我的意思是这样),我将能够连接这两个部分?

谢谢

OutputStream是你写数据的地方。 如果某个模块暴露了OutputStream ,则期望在另一端正在读取某些内容。

另一方面,暴露InputStream东西是指示你需要监听这个stream,并且会有你可以读取的数据。

所以可以将一个InputStream连接到一个OutputStream

InputStream----read---> intermediateBytes[n] ----write----> OutputStream

正如有人提到的,这是IOUtils的copy()方法允许你做的。 换个方式是没有意义的…希望这是有道理的

更新:

当然,我越想到这一点,我越能看到这实际上是一个需求。 我知道一些评论提到Pipedinput/输出stream,但还有另一种可能性。

如果显示的输出stream是ByteArrayOutputStream ,则可以通过调用toByteArray()方法来获取全部内容。 然后,您可以使用ByteArrayInputStream子类创build一个inputstream包装器。 这两个是伪stream,它们基本上只是包装一个字节数组。 因此,以这种方式使用溪stream在技术上是可行的,但对我来说,这仍然是非常奇怪的…

似乎有很多链接和其他这样的东西,但没有使用pipe道的实际代码。 使用java.io.PipedInputStreamjava.io.PipedOutputStream的优点是没有额外的内存消耗。 ByteArrayOutputStream.toByteArray()返回原始缓冲区的一个副本,这意味着无论你在内存中有什么,你现在有两个副本。 然后写入InputStream意味着您现在有三份数据。

代码:

 // take the copy of the stream and re-write it to an InputStream PipedInputStream in = new PipedInputStream(); final PipedOutputStream out = new PipedOutputStream(in); new Thread(new Runnable() { public void run () { try { // write the original OutputStream to the PipedOutputStream originalByteArrayOutputStream.writeTo(out); } catch (IOException e) { // logging and exception handling should go here } } }).start(); 

此代码假定originalByteArrayOutputStreamByteArrayOutputStream因为它通常是唯一可用的输出stream,除非您正在写入文件。 我希望这有帮助! 关于这一点的好处是,因为它是在一个单独的线程中,它也是并行工作的,所以无论是消耗你的inputstream,也将stream出你的旧输出stream。 这是有益的,因为缓冲区可以保持较小,并且延迟更less,内存使用量更less。

你将需要一个中间类,它将缓冲之间。 每次调用InputStream.read(byte[]...) ,缓冲类将使用从OutputStream.write(byte[]...)传入的下一个块填充传入的字节数组。 由于块的大小可能不相同,因此适配器类将需要存储一定的数量,直到它具有足够的空间来填充读取缓冲区和/或能够存储任何缓冲区溢出。

本文有几个不同的方法来解决这个问题:

http://blog.ostermiller.org/convert-java-outputstream-inputstream

easystream开源库直接支持将OutputStream转换为InputStream: http : //io-tools.sourceforge.net/easystream/tutorial/tutorial.html

他们还列出了其他选项: http : //io-tools.sourceforge.net/easystream/OutputStream_to_InputStream.html

由于input输出stream只是起点和终点,解决的方法是将数据临时存储在字节数组中。 因此,您必须创build中间ByteArrayOutputStream ,从中创build用作新ByteArrayInputStreaminput的byte[]

 public void doTwoThingsWithStream(InputStream inStream, OutputStream outStream){ //create temporary bayte array output stream ByteArrayOutputStream baos = new ByteArrayOutputStream(); doFirstThing(inStream, baos); //create input stream from baos InputStream isFromFirstData = new ByteArrayInputStream(baos.toByteArray()); doSecondThing(isFromFirstData, outStream); } 

希望它有帮助。

 ByteArrayOutputStream buffer = (ByteArrayOutputStream) aOutputStream; byte[] bytes = buffer.toByteArray(); InputStream inputStream = new ByteArrayInputStream(bytes); 

我遇到了将ByteArrayOutputStream转换为ByteArrayOutputStream的相同问题,并通过使用ByteArrayOutputStream的派生类来解决此问题,该派生类能够返回ByteArrayInputStream ,该ByteArrayOutputStream的内部缓冲区进行初始化。 这种方式没有使用额外的内存,“转换”是非常快的:

 package info.whitebyte.utils; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; /** * This class extends the ByteArrayOutputStream by * providing a method that returns a new ByteArrayInputStream * which uses the internal byte array buffer. This buffer * is not copied, so no additional memory is used. After * creating the ByteArrayInputStream the instance of the * ByteArrayInOutStream can not be used anymore. * <p> * The ByteArrayInputStream can be retrieved using <code>getInputStream()</code>. * @author Nick Russler */ public class ByteArrayInOutStream extends ByteArrayOutputStream { /** * Creates a new ByteArrayInOutStream. The buffer capacity is * initially 32 bytes, though its size increases if necessary. */ public ByteArrayInOutStream() { super(); } /** * Creates a new ByteArrayInOutStream, with a buffer capacity of * the specified size, in bytes. * * @param size the initial size. * @exception IllegalArgumentException if size is negative. */ public ByteArrayInOutStream(int size) { super(size); } /** * Creates a new ByteArrayInputStream that uses the internal byte array buffer * of this ByteArrayInOutStream instance as its buffer array. The initial value * of pos is set to zero and the initial value of count is the number of bytes * that can be read from the byte array. The buffer array is not copied. This * instance of ByteArrayInOutStream can not be used anymore after calling this * method. * @return the ByteArrayInputStream instance */ public ByteArrayInputStream getInputStream() { // create new ByteArrayInputStream that respects the current count ByteArrayInputStream in = new ByteArrayInputStream(this.buf, 0, this.count); // set the buffer of the ByteArrayOutputStream // to null so it can't be altered anymore this.buf = null; return in; } } 

我把东西放在github上: https : //github.com/nickrussler/ByteArrayInOutStream

如果你想从InputStream中创build一个OutputStream,有一个基本的问题。 写入OutputStream的方法阻塞,直到完成。 所以当写入方法结束时结果是可用的。 这有两个后果:

  1. 如果只使用一个线程,则需要等到写完所有内容(因此需要将stream的数据存储在内存或磁盘中)。
  2. 如果要在完成之前访问数据,则需要第二个线程。

变体1可以使用字节数组或字段来实现。 变体1可以使用pipies(直接或者额外的抽象 – 例如RingBuffer或者其他注释中的google lib)来实现。

事实上,对于标准的Java,没有其他办法可以解决这个问题。 每个解决scheme都是其中一个的实现。

有一个概念叫做“延续”(详见维基百科 )。 在这种情况下基本上这意味着:

  • 有一个特殊的输出stream需要一定数量的数据
  • 如果达到了这个数量,那么这个数据stream就把控制权交给了它的一个特殊的inputstream
  • inputstream使得数据量可用,直到它被读取,然后,它将控制传递回输出stream

虽然有些语言内置了这个概念,对于Java,你需要一些“魔力”。 例如,来自apache的“commons-javaflow”实现了这样的Java。 缺点是这需要在构build时进行一些特殊的字节码修改。 所以把所有的东西都放在一个额外的库里,并且使用定制的构build脚本是有意义的。

尽pipe无法将OutputStream转换为InputStream,但Java提供了一种使用PipedOutputStream和PipedInputStream的方法,您可以通过关联的PipedInputStream将写入PipedOutputStream的数据变为可用。
有时回到我遇到类似的情况时处理第三方库,需要一个InputStream实例传递给他们,而不是一个OutputStream实例。
我解决这个问题的方法是使用PipedInputStream和PipedOutputStream。
顺便说一句,他们使用起来很棘手,你必须使用multithreading来实现你想要的。 我最近在github上发布了一个你可以使用的实现。
这是链接 。 你可以通过wiki来了解如何使用它。

旧的post,但可能会帮助别人,使用这种方式:

 OutputStream out = new ByteArrayOutputStream(); ... out.write(); ... ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(out.toString().getBytes())); 

我认为将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 – 您不需要手动处理数据排队