How to convert OutputStream to InputStream?
我正处于开发阶段,我有两个模块,其中一个模块的输出为
谢谢
似乎有许多链接和其他类似的东西,但没有实际的代码使用管道。使用
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | // 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 // note that in order for the below method to work, you need // to ensure that the data has finished writing to the // ByteArrayOutputStream originalByteArrayOutputStream.writeTo(out); } catch (IOException e) { // logging and exception handling should go here } finally { // close the PipedOutputStream here because we're done writing data // once this thread has completed its run if (out != null) { // close the PipedOutputStream cleanly out.close(); } } } }).start(); |
此代码假定
另一方面,暴露
因此可以将
正如有人所说,这就是ioutils中的
更新:
当然,我越是想到这一点,我就越能看出这实际上是一个要求。我知道一些评论提到了
如果公开的输出流是一个
由于输入和输出流只是起点和终点,所以解决方案是在字节数组中临时存储数据。因此,您必须创建中间
1 2 3 4 5 6 7 8 | 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); } |
希望它有帮助。
您将需要一个中间类,它将在中间类之间进行缓冲。每次调用
本文详细介绍了解决此问题的几种不同方法:
http://blog.ostermiller.org/convert-java-outputstream-inputstream
1 2 3 | ByteArrayOutputStream buffer = (ByteArrayOutputStream) aOutputStream; byte[] bytes = buffer.toByteArray(); InputStream inputStream = new ByteArrayInputStream(bytes); |
EasyStream开源库直接支持将输出流转换为输入流:http://io-tools.sourceforge.net/eaystream/tutorial/tutorial.html
它们还列出了其他选项:http://io-tools.sourceforge.net/easystream/outputstream_to_inputstream.html
我在将
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | 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 <wyn>getInputStream()</wyn>. * @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
库IO附加程序可能有用。例如,如果要使用
1 2 |
请注意,库有100%的单元测试覆盖率(当然,这是值得的!)在马文中心。Maven的依赖关系是:
1 2 3 4 5 | <dependency> <groupId>com.github.davidmoten</groupId> io-extras</artifactId> <version>0.1</version> </dependency> |
一定要检查更高版本。
从我的角度来看,java.io.pipedinputstream/java.io.pipedoutsptream是考虑的最佳选择。在某些情况下,您可能希望使用bytearrayinputstream/bytearrayinputstream。问题是您需要复制缓冲区来将BytearrayOutputStream转换为BytearrayOutputStream。此外,BytearrayOutpustream/BytearrayInputstream限制为2GB。这里是一个OutPoSt/EndoSt流实现,我写的是绕过BytayRayOuttStudio/BytErayRePixStand限制(Scala代码,但对于Java开发人员来说是容易理解的):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 | import java.io.{IOException, InputStream, OutputStream} import scala.annotation.tailrec /** Acts as a replacement for ByteArrayOutputStream * */ class HugeMemoryOutputStream(capacity: Long) extends OutputStream { private val PAGE_SIZE: Int = 1024000 private val ALLOC_STEP: Int = 1024 /** Pages array * */ private var streamBuffers: Array[Array[Byte]] = Array.empty[Array[Byte]] /** Allocated pages count * */ private var pageCount: Int = 0 /** Allocated bytes count * */ private var allocatedBytes: Long = 0 /** Current position in stream * */ private var position: Long = 0 /** Stream length * */ private var length: Long = 0 allocSpaceIfNeeded(capacity) /** Gets page count based on given length * * @param length Buffer length * @return Page count to hold the specified amount of data */ private def getPageCount(length: Long) = { var pageCount = (length / PAGE_SIZE).toInt + 1 if ((length % PAGE_SIZE) == 0) { pageCount -= 1 } pageCount } /** Extends pages array * */ private def extendPages(): Unit = { if (streamBuffers.isEmpty) { streamBuffers = new Array[Array[Byte]](ALLOC_STEP) } else { val newStreamBuffers = new Array[Array[Byte]](streamBuffers.length + ALLOC_STEP) Array.copy(streamBuffers, 0, newStreamBuffers, 0, streamBuffers.length) streamBuffers = newStreamBuffers } pageCount = streamBuffers.length } /** Ensures buffers are bug enough to hold specified amount of data * * @param value Amount of data */ private def allocSpaceIfNeeded(value: Long): Unit = { @tailrec def allocSpaceIfNeededIter(value: Long): Unit = { val currentPageCount = getPageCount(allocatedBytes) val neededPageCount = getPageCount(value) if (currentPageCount < neededPageCount) { if (currentPageCount == pageCount) extendPages() streamBuffers(currentPageCount) = new Array[Byte](PAGE_SIZE) allocatedBytes = (currentPageCount + 1).toLong * PAGE_SIZE allocSpaceIfNeededIter(value) } } if (value < 0) throw new Error("AllocSpaceIfNeeded < 0") if (value > 0) { allocSpaceIfNeededIter(value) length = Math.max(value, length) if (position > length) position = length } } /** * Writes the specified byte to this output stream. The general * contract for <wyn>write</wyn> is that one byte is written * to the output stream. The byte to be written is the eight * low-order bits of the argument <wyn>b</wyn>. The 24 * high-order bits of <wyn>b</wyn> are ignored. * <p> * Subclasses of <wyn>OutputStream</wyn> must provide an * implementation for this method. * * @param b the <wyn>byte</wyn>. */ @throws[IOException] override def write(b: Int): Unit = { val buffer: Array[Byte] = new Array[Byte](1) buffer(0) = b.toByte write(buffer) } /** * Writes <wyn>len</wyn> bytes from the specified byte array * starting at offset <wyn>off</wyn> to this output stream. * The general contract for <wyn>write(b, off, len)</wyn> is that * some of the bytes in the array <wyn>b</wyn> are written to the * output stream in order; element <wyn>b[off]</wyn> is the first * byte written and <wyn>b[off+len-1]</wyn> is the last byte written * by this operation. * <p> * The <wyn>write</wyn> method of <wyn>OutputStream</wyn> calls * the write method of one argument on each of the bytes to be * written out. Subclasses are encouraged to override this method and * provide a more efficient implementation. * <p> * If <wyn>b</wyn> is <wyn>null</wyn>, a * <wyn>NullPointerException</wyn> is thrown. * <p> * If <wyn>off</wyn> is negative, or <wyn>len</wyn> is negative, or * <wyn>off+len</wyn> is greater than the length of the array * <wyn>b</wyn>, then an <tt>IndexOutOfBoundsException</tt> is thrown. * * @param b the data. * @param off the start offset in the data. * @param len the number of bytes to write. */ @throws[IOException] override def write(b: Array[Byte], off: Int, len: Int): Unit = { @tailrec def writeIter(b: Array[Byte], off: Int, len: Int): Unit = { val currentPage: Int = (position / PAGE_SIZE).toInt val currentOffset: Int = (position % PAGE_SIZE).toInt if (len != 0) { val currentLength: Int = Math.min(PAGE_SIZE - currentOffset, len) Array.copy(b, off, streamBuffers(currentPage), currentOffset, currentLength) position += currentLength writeIter(b, off + currentLength, len - currentLength) } } allocSpaceIfNeeded(position + len) writeIter(b, off, len) } /** Gets an InputStream that points to HugeMemoryOutputStream buffer * * @return InputStream */ def asInputStream(): InputStream = { new HugeMemoryInputStream(streamBuffers, length) } private class HugeMemoryInputStream(streamBuffers: Array[Array[Byte]], val length: Long) extends InputStream { /** Current position in stream * */ private var position: Long = 0 /** * Reads the next byte of data from the input stream. The value byte is * returned as an <wyn>int</wyn> in the range <wyn>0</wyn> to * <wyn>255</wyn>. If no byte is available because the end of the stream * has been reached, the value <wyn>-1</wyn> is returned. This method * blocks until input data is available, the end of the stream is detected, * or an exception is thrown. * * <p> A subclass must provide an implementation of this method. * * @return the next byte of data, or <wyn>-1</wyn> if the end of the * stream is reached. */ @throws[IOException] def read: Int = { val buffer: Array[Byte] = new Array[Byte](1) if (read(buffer) == 0) throw new Error("End of stream") else buffer(0) } /** * Reads up to <wyn>len</wyn> bytes of data from the input stream into * an array of bytes. An attempt is made to read as many as * <wyn>len</wyn> bytes, but a smaller number may be read. * The number of bytes actually read is returned as an integer. * * <p> This method blocks until input data is available, end of file is * detected, or an exception is thrown. * * <p> If <wyn>len</wyn> is zero, then no bytes are read and * <wyn>0</wyn> is returned; otherwise, there is an attempt to read at * least one byte. If no byte is available because the stream is at end of * file, the value <wyn>-1</wyn> is returned; otherwise, at least one * byte is read and stored into <wyn>b</wyn>. * * <p> The first byte read is stored into element <wyn>b[off]</wyn>, the * next one into <wyn>b[off+1]</wyn>, and so on. The number of bytes read * is, at most, equal to <wyn>len</wyn>. Let k be the number of * bytes actually read; these bytes will be stored in elements * <wyn>b[off]</wyn> through <wyn>b[off+</wyn>k<wyn>-1]</wyn>, * leaving elements <wyn>b[off+</wyn>k<wyn>]</wyn> through * <wyn>b[off+len-1]</wyn> unaffected. * * <p> In every case, elements <wyn>b[0]</wyn> through * <wyn>b[off]</wyn> and elements <wyn>b[off+len]</wyn> through * <wyn>b[b.length-1]</wyn> are unaffected. * * <p> The <wyn>read(b,</wyn> <wyn>off,</wyn> <wyn>len)</wyn> method * for class <wyn>InputStream</wyn> simply calls the method * <wyn>read()</wyn> repeatedly. If the first such call results in an * <wyn>IOException</wyn>, that exception is returned from the call to * the <wyn>read(b,</wyn> <wyn>off,</wyn> <wyn>len)</wyn> method. If * any subsequent call to <wyn>read()</wyn> results in a * <wyn>IOException</wyn>, the exception is caught and treated as if it * were end of file; the bytes read up to that point are stored into * <wyn>b</wyn> and the number of bytes read before the exception * occurred is returned. The default implementation of this method blocks * until the requested amount of input data <wyn>len</wyn> has been read, * end of file is detected, or an exception is thrown. Subclasses are encouraged * to provide a more efficient implementation of this method. * * @param b the buffer into which the data is read. * @param off the start offset in array <wyn>b</wyn> * at which the data is written. * @param len the maximum number of bytes to read. * @return the total number of bytes read into the buffer, or * <wyn>-1</wyn> if there is no more data because the end of * the stream has been reached. * @see java.io.InputStream#read() */ @throws[IOException] override def read(b: Array[Byte], off: Int, len: Int): Int = { @tailrec def readIter(acc: Int, b: Array[Byte], off: Int, len: Int): Int = { val currentPage: Int = (position / PAGE_SIZE).toInt val currentOffset: Int = (position % PAGE_SIZE).toInt val count: Int = Math.min(len, length - position).toInt if (count == 0 || position >= length) acc else { val currentLength = Math.min(PAGE_SIZE - currentOffset, count) Array.copy(streamBuffers(currentPage), currentOffset, b, off, currentLength) position += currentLength readIter(acc + currentLength, b, off + currentLength, len - currentLength) } } readIter(0, b, off, len) } /** * Skips over and discards <wyn>n</wyn> bytes of data from this input * stream. The <wyn>skip</wyn> method may, for a variety of reasons, end * up skipping over some smaller number of bytes, possibly <wyn>0</wyn>. * This may result from any of a number of conditions; reaching end of file * before <wyn>n</wyn> bytes have been skipped is only one possibility. * The actual number of bytes skipped is returned. If <wyn>n</wyn> is * negative, the <wyn>skip</wyn> method for class <wyn>InputStream</wyn> always * returns 0, and no bytes are skipped. Subclasses may handle the negative * value differently. * * The <wyn>skip</wyn> method of this class creates a * byte array and then repeatedly reads into it until <wyn>n</wyn> bytes * have been read or the end of the stream has been reached. Subclasses are * encouraged to provide a more efficient implementation of this method. * For instance, the implementation may depend on the ability to seek. * * @param n the number of bytes to be skipped. * @return the actual number of bytes skipped. */ @throws[IOException] override def skip(n: Long): Long = { if (n < 0) 0 else { position = Math.min(position + n, length) length - position } } } } |
易于使用,无缓冲区重复,无2GB内存限制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | val out: HugeMemoryOutputStream = new HugeMemoryOutputStream(initialCapacity /*may be 0*/) out.write(...) ... val in1: InputStream = out.asInputStream() in1.read(...) ... val in2: InputStream = out.asInputStream() in2.read(...) ... |
虽然不能将OuttoSt流转换为输入流,但Java提供了一种使用PiPooOuttuStudio和PiPoDePixSt流的方法,您可以将数据写入到PiPoDoPutsStudio中,以便通过相关的PiPixIdStudio获得可用的数据流。
以前,我在处理第三方库时遇到了类似的情况,这些库要求将一个inputstream实例传递给它们,而不是输出流实例。
我解决此问题的方法是使用pipedinputstream和pipedoutputstream。
顺便说一下,它们很难使用,您必须使用多线程来实现您想要的。我最近在Github上发布了一个可以使用的实现。
这里是链接。你可以通过wiki了解如何使用它。
旧的帖子,但可以帮助其他人,使用以下方式:
1 2 3 4 5 | OutputStream out = new ByteArrayOutputStream(); ... out.write(); ... ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(out.toString().getBytes())); |
如果要从输入流生成输出流,则有一个基本问题。写入OutputStream块的方法,直到完成为止。因此,当写入方法完成时,结果是可用的。这有两个后果:
变量1可以使用字节数组或字段实现。变种1可以使用pipies实现(直接或通过额外的抽象实现——例如,ringbuffer或来自其他注释的google lib)。
事实上,用标准的Java,没有其他的方法来解决这个问题。每个解决方案都是其中一个的实现。
有一个概念叫做"延续"(详见维基百科)。在这种情况下,基本上这意味着:
- 有一个特殊的输出流需要一定数量的数据
- 如果到达ammount,则流将控制它的对应流,这是一个特殊的输入流。
- 输入流使数据量在被读取之前是可用的,此后,它将控制权传递回输出流。
虽然有些语言有这个概念,但对于Java来说,你需要一些"魔法"。例如,Apache中的"Cason JavaFLUW"实现了Java。缺点是这需要在构建时修改一些特殊的字节码。所以把所有的东西放在一个额外的库中,用定制的构建脚本是有意义的。