Como converter OutputStream para InputStream?


337

Estou no estágio de desenvolvimento, onde tenho dois módulos e, de um, obtive saída como um OutputStreame segundo, que aceita apenas InputStream. Sabe como converter OutputStreampara InputStream(e não vice-versa, eu quero dizer realmente desta forma) que vou ser capaz de se conectar essas duas partes?

obrigado



3
@ c0mrade, o op quer algo como IOUtils.copy, apenas na outra direção. Quando alguém grava em um OutputStream, ele fica disponível para outra pessoa usar em um InputStream. Isso é basicamente o que o PipedOutputStream / PipedInputStream faz. Infelizmente, os fluxos Piped não podem ser construídos a partir de outros fluxos.
precisa saber é o seguinte

então o PipedOutputStream / PipedInputStream é a solução?
Waypoint

Basicamente, para que o PipedStreams funcione no seu caso, o OutputStream precisa ser construído como new YourOutputStream(thePipedOutputStream)e new YourInputStream(thePipedInputStream)provavelmente não é assim que o seu fluxo funciona. Então, eu não acho que essa seja a solução.
precisa saber é o seguinte

Respostas:


109

Um OutputStreamé aquele em que você grava dados. Se algum módulo expuser um OutputStream, a expectativa é que haja algo lendo no outro extremo.

Algo que expõe um InputStream, por outro lado, indica que você precisará ouvir esse fluxo e haverá dados que você poderá ler.

Portanto, é possível conectar um InputStreama umOutputStream

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

Como alguém mencionou, é isso que o copy()método do IOUtils permite que você faça. Não faz sentido seguir para o outro lado ... espero que isso faça algum sentido

ATUALIZAR:

É claro que quanto mais penso nisso, mais posso ver como isso realmente seria um requisito. Conheço alguns dos comentários mencionados Pipedfluxos de entrada / saída, mas há outra possibilidade.

Se o fluxo de saída exposto for a ByteArrayOutputStream, você poderá obter todo o conteúdo chamando o toByteArray()método Em seguida, você pode criar um wrapper de fluxo de entrada usando a ByteArrayInputStreamsubclasse. Esses dois são pseudo-fluxos, ambos basicamente apenas envolvem uma matriz de bytes. Usar os fluxos dessa maneira, portanto, é tecnicamente possível, mas para mim ainda é muito estranho ...


4
copiar () fazer isso é OS de acordo com a API, eu preciso fazer para trás
Waypoint

11
Veja minha edição no topo, é necesarry para mim fazer alguma conversão
Waypoint

86
O caso de usuário é muito simples: imagine que você tenha uma biblioteca de serialização (por exemplo, serializando para JSON) e uma camada de transporte (por exemplo, Tomcat) que utilize um InputStream. Portanto, você precisa canalizar o OutputStream do JSON por uma conexão HTTP que deseja ler de um InputStream.
JBCP 21/02

6
Isso é útil no teste de unidade e você é super pedante em evitar tocar no sistema de arquivos.
31416 Jon

26
O comentário de @JBCP está no local. Outro caso de uso está usando o PDFBox para criar PDFs durante uma solicitação HTTP. PDFBox usando um OutputStream para salvar um objeto PDF e a API REST aceita um InputStream para responder ao cliente. Portanto, um OutputStream -> InputStream é um caso de uso do mundo real.
John Manko 12/09

200

Parece haver muitos links e outras coisas desse tipo, mas nenhum código real usando pipes. A vantagem de usar java.io.PipedInputStreame java.io.PipedOutputStreamé que não há consumo adicional de memória. ByteArrayOutputStream.toByteArray()retorna uma cópia do buffer original, o que significa que, o que quer que você tenha na memória, agora você tem duas cópias. Em seguida, escrevendo para um InputStreammeio, você agora tem três cópias dos dados.

O código:

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

Esse código pressupõe que o originalByteArrayOutputStreamé um ByteArrayOutputStream, pois geralmente é o único fluxo de saída utilizável, a menos que você esteja gravando em um arquivo. Eu espero que isso ajude! O melhor disso é que, como está em um encadeamento separado, ele também está trabalhando em paralelo; portanto, o que estiver consumindo seu fluxo de entrada também sairá do seu antigo fluxo de saída. Isso é benéfico porque o buffer pode permanecer menor e você terá menos latência e menos uso de memória.


21
Votei a favor, mas é melhor passar outpara ino construtor, caso contrário, você poderá receber uma exceção de tubo fechado indevido à condição de corrida (que eu experimentei). Usando Java 8 Lambdas:PipedInputStream in = new PipedInputStream(out); ((Runnable)() -> {originalOutputStream.writeTo(out);}).run(); return in;
John Manko

11
@JohnManko hmm ... Eu nunca tive esse problema. Você experimentou isso porque outro thread ou o thread principal está chamando out.close ()? É verdade que esse código pressupõe que seu PipedOutputStream tenha uma vida útil mais longa que a sua, o originalOutputStreamque deve ser verdadeiro, mas não assume como você controla seus fluxos. Isso é deixado para o desenvolvedor. Não há nada neste código que possa causar uma exceção de canal fechado ou quebrado.
Mikeho

3
Não, meu caso decorre de quando armazeno PDFs no Mongo GridFS e depois transmito para o cliente usando Jax-RS. O MongoDB fornece um OutputStream, mas o Jax-RS requer um InputStream. Meu método path retornaria ao contêiner com um InputStream antes que o OutputStream estivesse totalmente estabelecido, ao que parece (talvez o buffer ainda não tivesse sido armazenado em cache). De qualquer forma, o Jax-RS lançaria uma exceção de pipe fechado no InputStream. Estranho, mas foi o que aconteceu metade do tempo. Mudar para o código acima impede isso.
John Manko 14/09

11
@JohnManko Eu estava analisando mais isso e vi pelos PipedInputStreamJavadocs: Diz-se que um pipe está quebrado se um encadeamento que estava fornecendo bytes de dados para o fluxo de saída canalizado conectado não estiver mais ativo. Então, o que eu suspeito é que, se você estiver usando o exemplo acima, o encadeamento está sendo concluído antes Jax-RSe consumindo o fluxo de entrada. Ao mesmo tempo, observei os Javadocs do MongoDB . GridFSDBFiletem um fluxo de entrada, então por que não passar isso para o Jax-RS ?
Mikeho 15/09/2015

3
@DennisCheung sim, é claro. Nada é gratuito, mas certamente será menor que uma cópia de 15 MB. As otimizações incluiriam o uso de um conjunto de encadeamentos para reduzir a rotatividade do GC com a criação constante de encadeamentos / objetos.
Mikeho 27/07/16

40

Como os fluxos de entrada e saída são apenas o ponto inicial e final, a solução é armazenar dados temporariamente na matriz de bytes. Portanto, você deve criar intermediários ByteArrayOutputStream, a partir dos quais você cria, byte[]que é usado como entrada para novos 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);
}

Espero que ajude.


baos.toByteArray () cria uma cópia com System.arraycopy. Obrigado a @mikeho por apontar developer.classpath.org/doc/java/io/…
Mitja Gustin

20

Você precisará de uma classe intermediária que fará o buffer entre. Cada vez que InputStream.read(byte[]...)é chamada, a classe de buffer preenche a matriz de bytes passada com o próximo pedaço passado de OutputStream.write(byte[]...). Como os tamanhos dos chunks podem não ser os mesmos, a classe do adaptador precisará armazenar uma certa quantia até ter o suficiente para preencher o buffer de leitura e / ou poder armazenar qualquer estouro de buffer.

Este artigo possui uma boa descrição de algumas abordagens diferentes para esse problema:

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


11
obrigado @mckamey, o método baseado em amortecedores circulares é exatamente o que eu preciso!
Hui Wang

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

2
Você não deve usar isso, pois o toByteArray()corpo do método é assim, return Arrays.copyOf(buf, count);e retorna uma nova matriz.
Root G


9

Encontrei o mesmo problema ao converter a ByteArrayOutputStreamem a ByteArrayInputStreame resolvi-o usando uma classe derivada da ByteArrayOutputStreamqual é possível retornar um ByteArrayInputStreamque é inicializado com o buffer interno do ByteArrayOutputStream. Dessa forma, nenhuma memória adicional é usada e a 'conversão' é muito rápida:

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

Coloquei as coisas no github: https://github.com/nickrussler/ByteArrayInOutStream


e se o conteúdo não couber no buffer?
Vadimo 15/09

Então você não deve usar um ByteArrayInputStream em primeiro lugar.
precisa saber é o seguinte

Esta solução terá todos os bytes na memória. Para arquivos pequenos, tudo ficará bem, mas você também pode usar getBytes () no ByteArrayOutput Stream
Vadimo

11
Se você quer dizer ByByteArray, isso fará com que o buffer interno seja copiado, o que consumirá o dobro da memória da minha abordagem. Edit: Ah, eu entendo, para arquivos pequenos, isso funciona, é claro ..
Nick Russler 15/14

Perda de tempo. O ByteArrayOutputStream possui um método writeTo para transferir o conteúdo para outro fluxo de saída
Tony BenBrahim

3

A biblioteca io-extras pode ser útil. Por exemplo, se você deseja compactar um zip com um InputStreamuso GZIPOutputStreame deseja que isso ocorra de forma síncrona (usando o tamanho padrão do buffer 8192):

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

Observe que a biblioteca possui 100% de cobertura de teste de unidade (pelo que vale a pena, é claro!) E está no Maven Central. A dependência do Maven é:

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

Certifique-se de verificar se há uma versão posterior.


0

Do meu ponto de vista, java.io.PipedInputStream / java.io.PipedOutputStream é a melhor opção para considerar. Em algumas situações, convém usar ByteArrayInputStream / ByteArrayOutputStream. O problema é que você precisa duplicar o buffer para converter um ByteArrayOutputStream em um ByteArrayInputStream. ByteArrayOutpuStream / ByteArrayInputStream também são limitados a 2 GB. Aqui está uma implementação OutpuStream / InputStream que escrevi para ignorar as limitações de ByteArrayOutputStream / ByteArrayInputStream (código Scala, mas facilmente compreensível para desenvolvedores 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
      }
    }
  }
}

Fácil de usar, sem duplicação de buffer, sem limite de memória de 2 GB

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

Se você deseja criar um OutputStream a partir de um InputStream, há um problema básico. Um método que grava em um OutputStream bloqueia até que seja concluído. Portanto, o resultado está disponível quando o método de gravação é concluído. Isso tem duas consequências:

  1. Se você usar apenas um encadeamento, precisará aguardar até que tudo seja gravado (para armazenar os dados do fluxo na memória ou no disco).
  2. Se você deseja acessar os dados antes de concluí-los, precisará de um segundo encadeamento.

A variante 1 pode ser implementada usando matrizes de bytes ou arquivadas. A variante 1 pode ser implementada usando pipies (diretamente ou com abstração extra - por exemplo, RingBuffer ou google lib do outro comentário).

De fato, com o java padrão, não há outra maneira de resolver o problema. Cada solução é uma implementação de um deles.

Há um conceito chamado "continuação" (consulte a Wikipedia para detalhes). Neste caso, basicamente, isso significa:

  • existe um fluxo de saída especial que espera uma certa quantidade de dados
  • se a quantidade for atingida, o fluxo controlará sua contraparte, que é um fluxo de entrada especial
  • o fluxo de entrada disponibiliza a quantidade de dados até que seja lida; depois disso, ele passa o controle de volta ao fluxo de saída

Enquanto algumas linguagens têm esse conceito embutido, para o java você precisa de alguma "mágica". Por exemplo, "commons-javaflow" do apache implementa como o java. A desvantagem é que isso requer algumas modificações especiais de código de byte no tempo de construção. Portanto, faria sentido colocar todas as coisas em uma biblioteca extra com scripts de construção personalizados.


-1

Postagem antiga, mas pode ajudar outras pessoas, use desta maneira:

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

11
para String -> problema de tamanho
user1594895 9/10

Além disso, chamar toString().getBytes()um fluxo * não retornará o conteúdo do fluxo.
Maarten Bodewes

-1

Embora você não possa converter um OutputStream em um InputStream, o java fornece uma maneira, usando PipedOutputStream e PipedInputStream, de que você pode ter dados gravados em um PipedOutputStream para se tornarem disponíveis através de um PipedInputStream associado.
Algum tempo atrás, enfrentei uma situação semelhante ao lidar com bibliotecas de terceiros que exigiam que uma instância InputStream fosse passada a elas, em vez de uma instância OutputStream.
A maneira que eu corrigi esse problema é usar o PipedInputStream e o PipedOutputStream.
A propósito, eles são difíceis de usar e você deve usar o multithreading para conseguir o que deseja. Publiquei recentemente uma implementação no github que você pode usar.
Aqui está o link . Você pode acessar o wiki para entender como usá-lo.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.