OutputStreamをInputStreamに変換する方法は?


337

私は開発の段階にあり、2つのモジュールがあり、1つからはとして出力され、OutputStream2つ目はのみを受け入れますInputStream。これらの2つのパーツを接続できるように(その逆ではなく、実際にはこの方法で)変換OutputStreamする方法を知っていますInputStreamか?

ありがとう



3
@ c0mrade、opはIOUtils.copyのようなものを反対方向にのみ望んでいます。誰かがOutputStreamに書き込むと、他の誰かがInputStreamで使用できるようになります。これは基本的にPipedOutputStream / PipedInputStreamが行うことです。残念ながら、パイプストリームは他のストリームから構築できません。
MeBigFatGuy

PipedOutputStream / PipedInputStreamが解決策ですか?
ウェイポイント2011

基本的にPipedStreamsがあなたのケースで機能するためには、あなたのOutputStreamはのように構築する必要がありnew YourOutputStream(thePipedOutputStream)new YourInputStream(thePipedInputStream)これはおそらくあなたのストリームが機能する方法ではありません。だから私はこれが解決策だとは思いません。
MeBigFatGuy

回答:


109

アンは、OutputStreamあなたがにデータを書き込むものです。一部のモジュールがを公開するOutputStream場合、期待されるのは、反対側で何かが読み取られることです。

InputStream一方、を公​​開するものは、このストリームをリッスンする必要があり、読み取ることができるデータがあることを示しています。

だから、接続することが可能であるInputStreamOutputStream

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

誰かcopy()言及したように、これはIOUtilsのメソッドで実行できるものです。逆に行くのは意味がありません...うまくいけば、これはいくつかの意味があります

更新:

もちろん、私がこれについて考えれば考えるほど、これが実際にどのように要件であるかがわかります。Piped入力/出力ストリームに言及したコメントの一部を知っていますが、別の可能性があります。

公開されている出力ストリームがの場合、メソッドをByteArrayOutputStream呼び出すことで常に完全なコンテンツを取得できますtoByteArray()。次に、ByteArrayInputStreamサブクラスを使用して入力ストリームラッパーを作成できます。これら2つは疑似ストリームであり、どちらも基本的にはバイトの配列をラップするだけです。したがって、この方法でストリームを使用することは技術的には可能ですが、私にはまだ非常に奇妙です...


4
copy()APIに従ってこれをOSに実行します。逆方向に実行する必要があります
ウェイポイント

1
私はいくつかの変換にするために上に私の編集を参照してください、それがnecesarryです
ウェイポイント

86
ユースケースは非常に単純です。たとえば、シリアル化ライブラリ(JSONへのシリアル化など)と、InputStreamを受け取るトランスポートレイヤー(たとえば、Tomcat)があるとします。したがって、InputStreamから読み取りたいHTTP接続を介してJSONからOutputStreamをパイプする必要があります。
JBCP 2014

6
これは、単体テストを行っているときに、ファイルシステムへのアクセスを回避することに精通している場合に役立ちます。
Jon

26
@JBCPのコメントがスポットです。別の使用例は、HTTPリクエスト中にPDFBoxを使用してPDFを作成することです。OutputStreamを使用してPDFオブジェクトを保存するPDFBox。RESTAPIは、InputStreamを受け入れてクライアントに応答します。したがって、OutputStream-> InputStreamは実際の使用例です。
John Manko

200

リンクなどはたくさんあるようですが、パイプを使用した実際のコードはありません。java.io.PipedInputStreamおよびを使用する利点はjava.io.PipedOutputStream、メモリの追加消費がないことです。ByteArrayOutputStream.toByteArray()は元のバッファのコピーを返します。つまり、メモリにあるものは何でも、2つのコピーを持つことになります。次に、InputStream手段に書き込むと、データのコピーが3つ作成されます。

コード:

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

このコードは、ことを前提としてoriginalByteArrayOutputStreamいるByteArrayOutputStreamあなたは、ファイルへの書き込みをしている場合を除き、それは、通常は使用可能な出力ストリームであるとして。これが役に立てば幸いです!これの素晴らしい点は、別のスレッドにあるため、並行して動作しているため、入力ストリームを消費しているものは何でも古い出力ストリームからストリーミングされることです。バッファを小さくすることができ、レイテンシとメモリ使用量が少なくなるため、これは有益です。


21
私はこれに賛成票を投じましたが、のコンストラクタに渡すoutことをinお勧めします。そうしないと、in競合状態(私が経験したもの)が原因でクローズドパイプ例外が発生する可能性があります。Java 8 Lambdasの使用:PipedInputStream in = new PipedInputStream(out); ((Runnable)() -> {originalOutputStream.writeTo(out);}).run(); return in;
John Manko

1
@JohnMankoうーん...私はその問題を持ったことがありません。別のスレッドまたはメインスレッドがout.close()を呼び出しているため、これを経験しましたか?このコードは、PipedOutputStreamが、本来originalOutputStreamあるべきものよりも長寿命であることを前提としていますが、ストリームの制御方法は想定していません。それは開発者に任されています。このコードには、閉じたパイプや壊れたパイプの例外を引き起こすものはありません。
mikeho

3
いいえ、私のケースは、Mongo GridFSにPDFを保存してから、Jax-RSを使用してクライアントにストリーミングした場合に発生します。MongoDBはOutputStreamを提供しますが、Jax-RSにはInputStreamが必要です。私のパスメソッドは、OutputStreamが完全に確立される前に、InputStreamを使用してコンテナーに戻ります(おそらく、バッファーはまだキャッシュされていません)。とにかく、Jax-RSはInputStreamでパイプが閉じた例外をスローします。奇妙ですが、それは半分の時間に起こったことです。上記のコードに変更すると、それを防ぐことができます。
John Manko

1
@JohnManko私はからこれ以上、私のこぎりに探していたPipedInputStreamのJavadoc:データを提供していたスレッドがもはや生きて接続されているパイプで連結された出力ストリームにバイトをしない場合はAのパイプが壊れていると言われています。だから私が疑っているのは、上記の例を使用している場合、スレッドがJax-RS入力ストリームを消費する前に完了していることです。同時に、MongoDBの Javadoc も調べました。GridFSDBFile入力ストリームがあるので、それをJax-RSに渡してみませんか?
mikeho

3
@DennisCheungええ、もちろん。無料のものはありませんが、15MBのコピーよりも確実に小さくなります。最適化では、代わりにスレッドプールを使用して、一定のスレッド/オブジェクトの作成によるGCチャーンを減らします。
mikeho

40

入力ストリームと出力ストリームは開始点と終了点にすぎないため、解決策はデータをバイト配列に一時的に格納することです。だから、中間作成する必要がありByteArrayOutputStream、そこからあなたが作成し、byte[]それが新しいのための入力として使用されますByteArrayInputStream

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

それが役に立てば幸い。


baos.toByteArray()は、System.arraycopyでコピーを作成します。指摘し@mikehoのおかげdeveloper.classpath.org/doc/java/io/...
Mitja Gustin

20

バッファリングする中間クラスが必要になります。InputStream.read(byte[]...)呼び出されるたびに、バッファリングクラスは、渡されたバイト配列を、から渡された次のチャンクで埋めOutputStream.write(byte[]...)ます。チャンクのサイズが同じでない場合があるため、アダプタークラスは、読み取りバッファーをいっぱいにするか、バッファーオーバーフローを格納できるようになるまで、一定量を格納する必要があります。

この記事には、この問題へのいくつかの異なるアプローチのすばらしい内訳があります。

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


1
@mckameyに感謝します。循環バッファーに基づく方法は、まさに私が必要とするものです!
Hui Wang

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

2
toByteArray()メソッド本体は次のようになりreturn Arrays.copyOf(buf, count);、新しい配列を返すため、これを使用しないでください。
ルートG


9

a ByteArrayOutputStreamをaに変換するときに同じ問題が発生し、の内部バッファーで初期化されたaを返すことができるByteArrayInputStream派生クラスを使用して解決しました。この方法では、追加のメモリは使用されず、「変換」は非常に高速です。ByteArrayOutputStreamByteArrayInputStreamByteArrayOutputStream

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


コンテンツがバッファーに収まらない場合はどうなりますか?
Vadimo

その場合、最初にByteArrayInputStreamを使用しないでください。
Nick Russler、2014

このソリューションでは、メモリ内にすべてのバイトがあります。小さなファイルの場合はこれで問題ありませんが、ByteArrayOutputストリームでgetBytes()を使用することもできます
Vadimo

1
toByteArrayを意味する場合、これにより内部バッファーがコピーされ、私のアプローチの2倍のメモリーが必要になります。編集:小さなファイルのためにああ、私は理解して、もちろんこの作品...
ニックRussler

時間の無駄。ByteArrayOutputStreamには、コンテンツを別の出力ストリームに転送するためのwriteToメソッドがあります
Tony BenBrahim

3

ライブラリio-extrasが役立つ場合があります。たとえば、あなたは、gzip圧縮するかどうInputStream使ってGZIPOutputStream、あなたはそれが起こるしたい同期(8192のデフォルトのバッファサイズを使用して):

InputStream is = ...
InputStream gz = IOUtil.pipe(is, o -> new GZIPOutputStream(o));

ライブラリは100%の単体テストカバレッジ(当然のことですが)であり、Maven Centralにあることに注意してください。Mavenの依存関係は次のとおりです。

<dependency>
  <groupId>com.github.davidmoten</groupId>
  <artifactId>io-extras</artifactId>
  <version>0.1</version>
</dependency>

新しいバージョンを必ず確認してください。


0

私の見解では、java.io.PipedInputStream / java.io.PipedOutputStreamを検討するのに最適なオプションです。状況によっては、ByteArrayInputStream / ByteArrayOutputStreamを使用したい場合があります。問題は、ByteArrayOutputStreamをByteArrayInputStreamに変換するためにバッファを複製する必要があることです。また、ByteArrayOutpuStream / ByteArrayInputStreamは2GBに制限されています。これは、ByteArrayOutputStream / ByteArrayInputStreamの制限を回避するために私が書いたOutpuStream / InputStreamの実装です(Scalaコードですが、Java開発者には簡単に理解できます)。

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 <code>write</code> is that one byte is written
    * to the output stream. The byte to be written is the eight
    * low-order bits of the argument <code>b</code>. The 24
    * high-order bits of <code>b</code> are ignored.
    * <p>
    * Subclasses of <code>OutputStream</code> must provide an
    * implementation for this method.
    *
    * @param      b the <code>byte</code>.
    */
  @throws[IOException]
  override def write(b: Int): Unit = {
    val buffer: Array[Byte] = new Array[Byte](1)

    buffer(0) = b.toByte

    write(buffer)
  }

  /**
    * Writes <code>len</code> bytes from the specified byte array
    * starting at offset <code>off</code> to this output stream.
    * The general contract for <code>write(b, off, len)</code> is that
    * some of the bytes in the array <code>b</code> are written to the
    * output stream in order; element <code>b[off]</code> is the first
    * byte written and <code>b[off+len-1]</code> is the last byte written
    * by this operation.
    * <p>
    * The <code>write</code> method of <code>OutputStream</code> 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 <code>b</code> is <code>null</code>, a
    * <code>NullPointerException</code> is thrown.
    * <p>
    * If <code>off</code> is negative, or <code>len</code> is negative, or
    * <code>off+len</code> is greater than the length of the array
    * <code>b</code>, 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 <code>int</code> in the range <code>0</code> to
      * <code>255</code>. If no byte is available because the end of the stream
      * has been reached, the value <code>-1</code> 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 <code>-1</code> 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 <code>len</code> bytes of data from the input stream into
      * an array of bytes.  An attempt is made to read as many as
      * <code>len</code> 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 <code>len</code> is zero, then no bytes are read and
      * <code>0</code> 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 <code>-1</code> is returned; otherwise, at least one
      * byte is read and stored into <code>b</code>.
      *
      * <p> The first byte read is stored into element <code>b[off]</code>, the
      * next one into <code>b[off+1]</code>, and so on. The number of bytes read
      * is, at most, equal to <code>len</code>. Let <i>k</i> be the number of
      * bytes actually read; these bytes will be stored in elements
      * <code>b[off]</code> through <code>b[off+</code><i>k</i><code>-1]</code>,
      * leaving elements <code>b[off+</code><i>k</i><code>]</code> through
      * <code>b[off+len-1]</code> unaffected.
      *
      * <p> In every case, elements <code>b[0]</code> through
      * <code>b[off]</code> and elements <code>b[off+len]</code> through
      * <code>b[b.length-1]</code> are unaffected.
      *
      * <p> The <code>read(b,</code> <code>off,</code> <code>len)</code> method
      * for class <code>InputStream</code> simply calls the method
      * <code>read()</code> repeatedly. If the first such call results in an
      * <code>IOException</code>, that exception is returned from the call to
      * the <code>read(b,</code> <code>off,</code> <code>len)</code> method.  If
      * any subsequent call to <code>read()</code> results in a
      * <code>IOException</code>, the exception is caught and treated as if it
      * were end of file; the bytes read up to that point are stored into
      * <code>b</code> 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 <code>len</code> 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 <code>b</code>
      *                 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
      *         <code>-1</code> 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 <code>n</code> bytes of data from this input
      * stream. The <code>skip</code> method may, for a variety of reasons, end
      * up skipping over some smaller number of bytes, possibly <code>0</code>.
      * This may result from any of a number of conditions; reaching end of file
      * before <code>n</code> bytes have been skipped is only one possibility.
      * The actual number of bytes skipped is returned. If <code>n</code> is
      * negative, the <code>skip</code> method for class <code>InputStream</code> always
      * returns 0, and no bytes are skipped. Subclasses may handle the negative
      * value differently.
      *
      * The <code>skip</code> method of this class creates a
      * byte array and then repeatedly reads into it until <code>n</code> 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のメモリ制限なし

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(...)
...

-1

InputStreamからOutputStreamを作成する場合、1つの基本的な問題があります。OutputStreamに書き込むメソッドは、完了するまでブロックします。したがって、結果は書き込みメソッドが終了したときに利用できます。これには2つの結果があります。

  1. スレッドを1つだけ使用する場合は、すべてが書き込まれるまで待つ必要があります(そのため、ストリームのデータをメモリまたはディスクに格納する必要があります)。
  2. 終了する前にデータにアクセスする場合は、2番目のスレッドが必要です。

バリアント1は、バイト配列またはフィールドを使用して実装できます。バリアント1は、pipiを使用して実装できます(直接または追加の抽象化を使用して、RingBufferや他のコメントのgoogle libなど)。

確かに標準のJavaでは、問題を解決する他の方法はありません。各ソリューションは、これらのいずれかの実装です。

「継続」と呼ばれる概念が1つあります(詳細については、ウィキペディアを参照してください)。この場合、基本的にこれは次のことを意味します。

  • 特定の量のデータを期待する特別な出力ストリームがあります
  • ammountに達した場合、ストリームは対応するものを制御します。これは特別な入力ストリームです
  • 入力ストリームは、読み取られるまでデータの量を使用可能にし、その後、制御を出力ストリームに戻します。

一部の言語にはこの概念が組み込まれていますが、Javaの場合は「魔法」が必要です。たとえば、Apacheの "commons-javaflow"は、java用にそのようなものを実装しています。欠点は、ビルド時に特別なバイトコードの変更が必要になることです。したがって、カスタムビルドスクリプトを使用して、すべてのものを追加のライブラリに配置することは理にかなっています。


-1

古い投稿ですが、他の人を助けるかもしれません、このように使用してください:

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

1
文字列に->サイズの問題
user1594895 14年

また、toString().getBytes()ストリームを呼び出すと、ストリームのコンテンツは返されません。
Maarten Bodewes 2016

-1

OutputStreamをInputStreamに変換することはできませんが、JavaはPipedOutputStreamおよびPipedInputStreamを使用して、データをPipedOutputStreamに書き込み、関連するPipedInputStreamを介して使用できるようにする方法を提供します。
ときどき、OutputStreamインスタンスではなくInputStreamインスタンスを渡す必要があるサードパーティのライブラリを扱うときに、同じような状況に直面しました。
この問題を修正する方法は、PipedInputStreamとPipedOutputStreamを使用することです。
ちなみに、それらは使用するのが難しいので、マルチスレッドを使用して目的を達成する必要があります。私は最近、あなたが使用できる実装をgithubに公開しました。
こちらがリンクです。あなたはそれをどのように使うかを理解するためにウィキを通過することができます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.