Nasıl OutputStream InputStream dönüştürmek için?


337

İki modülüm olduğu ve birinden OutputStreamikincisi olarak çıktı aldığım , sadece kabul eden geliştirme aşamasındayım InputStream. Dönüştürmek biliyor musunuz OutputStreamiçin InputStreambu iki parça bağlamak mümkün olacağını (, gerçekten bu şekilde ifade tersi değil)?

Teşekkürler



3
@ c0mrade, op yalnızca diğer yönde IOUtils.copy gibi bir şey istiyor. Birisi bir OutputStream'e yazdığında, bir başkasının InputStream'de kullanması mümkün olur. Temelde PipedOutputStream / PipedInputStream bunu yapar. Maalesef Piped akışları diğer akışlardan oluşturulamaz.
Mayıs

PipedOutputStream / PipedInputStream çözüm nedir?
Waypoint

Temel olarak PipedStreams'in sizin durumunuzda çalışması için OutputStream'inizin benzer şekilde yapılandırılması gerekir new YourOutputStream(thePipedOutputStream)ve new YourInputStream(thePipedInputStream)bu muhtemelen akışınızın çalışma şekli değildir. Bu yüzden çözüm olduğunu sanmıyorum.
Mayıs

Yanıtlar:


109

An OutputStream, veri yazdığınız yerdir. Bazı modüllerde bir pozlama varsa OutputStream, diğer uçta okunan bir şey olması beklenir.

InputStreamÖte yandan, bir şeyi ortaya çıkaran bir şey, bu akışı dinlemeniz gerekeceğini ve okuyabileceğiniz veriler olacağını gösterir.

Böylece InputStreambirOutputStream

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

Birisi metrik olarak, IOUtils'in copy()yönteminin bunu yapmasına izin verir. Diğer yöne gitmek mantıklı değil ... umarım bu biraz mantıklıdır

GÜNCELLEME:

Tabii bunu ne kadar çok düşünürsem, bunun aslında nasıl bir gereklilik olacağını daha fazla görebiliyorum. PipedGiriş / çıkış akışlarından bahsi geçen yorumlardan bazılarını biliyorum , ancak başka bir olasılık var.

Açığa çıkan çıkış akışı bir ise, yöntemi ByteArrayOutputStreamçağırarak her zaman tüm içeriği alabilirsiniz toByteArray(). Sonra ByteArrayInputStreamalt sınıfı kullanarak bir girdi akışı sarmalayıcısı oluşturabilirsiniz . Bu ikisi sahte akışlardır, her ikisi de temelde sadece bir bayt dizisini sarar. Bu nedenle, akışları bu şekilde kullanmak teknik olarak mümkündür, ancak bana göre hala çok garip ...


4
copy () API'ye göre OS'ye IS yapıyor, geriye doğru yapmam gerekiyor
Waypoint

1
Üstteki düzenlememi görün, bazı dönüşümler yapmak benim için gerekli
Waypoint

88
Usecase çok basit: Bir serileştirme kitaplığınız (örneğin, JSON'a serileştirme) ve bir InputStream alan bir taşıma katmanı (örneğin, Tomcat) olduğunu düşünün. Bu nedenle, InputStream öğesinden okumak isteyen bir HTTP bağlantısı üzerinden OutputStream'i JSON'dan ayırmanız gerekir.
JBCP

6
Bu, birim testi yaparken kullanışlıdır ve dosya sistemine dokunmaktan kaçınmak konusunda aşırı bilgilisiniz.
Jon

28
@JBCP adlı kullanıcının yorumu yerinde. Başka bir kullanım örneği, HTTP isteği sırasında PDF oluşturmak için PDFBox kullanmaktır. Bir PDF nesnesini kaydetmek için bir OutputStream kullanarak PDFBox ve REST API istemciye yanıt vermek için bir InputStream kabul eder. Bu nedenle, bir OutputStream -> InputStream çok gerçek dünyadaki bir kullanım durumudur.
John Manko

200

Birçok bağlantı ve benzeri şeyler var gibi görünüyor, ancak borular kullanan gerçek bir kod yok. Kullanmanın avantajı java.io.PipedInputStreamve java.io.PipedOutputStreamek bellek tüketimi olmamasıdır. ByteArrayOutputStream.toByteArray()orijinal arabelleğin bir kopyasını döndürür, böylece bellekte ne varsa, şimdi iki kopyasına sahip olursunuz. Sonra bir ortama yazdığınızda InputStreamartık verilerin üç kopyası var.

Kod:

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

Bu kod , bir dosyaya yazmadığınız sürece, genellikle kullanılabilir tek çıkış akışı olduğu için originalByteArrayOutputStreambunun a olduğunu varsayar ByteArrayOutputStream. Umarım bu yardımcı olur! Bununla ilgili en güzel şey, ayrı bir iş parçacığında olduğu için, paralel olarak da çalışmasıdır, bu nedenle giriş akışınızı tüketen her şey, eski çıkış akışınızdan da akacaktır. Arabellek daha küçük kalabilir ve daha az gecikme süresi ve daha az bellek kullanımı elde edersiniz.


21
Ben bu oy verilen, ancak geçmek daha iyidir outiçin inaksi takdirde kapalı bir boru istisna alabilirsiniz, 'ın yapıcısı in(Deneyimli) yarış durumu nedeniyle. Java 8 Lambdas'ı kullanma:PipedInputStream in = new PipedInputStream(out); ((Runnable)() -> {originalOutputStream.writeTo(out);}).run(); return in;
John Manko

1
@JohnManko hmm ... Hiç böyle bir sorun yaşamadım. Başka bir iş parçacığı veya ana iş parçacığı out.close () çağırdığı için bunu yaşadınız mı? Bu kod, PipedOutputStream öğenizin sizin doğru olması gerekenden daha uzun ömürlü olduğunu varsayar originalOutputStream, ancak akışlarınızı nasıl kontrol ettiğiniz varsayılmaz. Bu geliştiriciye bırakılmıştır. Bu kodda kapalı veya kırık bir boru istisnasına neden olacak hiçbir şey yoktur.
mikeho

3
Hayır, benim durumum PDF'leri Mongo GridFS'de sakladığımdan ve ardından Jax-RS kullanarak istemciye akışımdan kaynaklanıyor. MongoDB bir OutputStream sağlar, ancak Jax-RS bir InputStream gerektirir. Benim yol yöntemi OutputStream tamamen oluşturulmadan önce bir InputStream ile kapsayıcı dönecekti, görünüşe göre (belki de tampon henüz önbelleğe alınmamıştı). Her neyse, Jax-RS, InputStream'e boru kapalı istisnasını atacaktı. Garip, ama yarıda böyle oldu. Yukarıdaki kodu değiştirmek bunu engeller.
John Manko

1
@JohnManko Bunu daha fazla inceliyordum ve PipedInputStreamJavadocs'tan gördüm : Bağlı borulu çıkış akışına veri baytları sağlayan bir iş parçacığı artık canlı değilse, bir borunun kırıldığı söylenir. Şüpheleniyorum, yukarıdaki örneği kullanıyorsanız, iş parçacığı daha önce tamamlanıyor Jax-RSgiriş akışını tüketiyor. Aynı zamanda MongoDB Javadocs'a da baktım . GridFSDBFilegiriş akışı var, neden bunu sadece Jax-RS'e iletmiyorsunuz ?
mikeho

3
@DennisCheung evet, elbette. Hiçbir şey ücretsiz değil, ama kesinlikle 15 MB'lık bir kopyadan daha küçük olacak. Optimizasyonlar, sabit iplik / nesne oluşturma ile GC karmaşasını azaltmak için bunun yerine bir iplik havuzu kullanmayı içerir.
mikeho

40

Giriş ve çıkış akışları sadece başlangıç ​​ve bitiş noktası olduğundan, çözüm verileri bayt dizisinde geçici olarak saklamaktır. Bu nedenle ByteArrayOutputStream, byte[]yeni için girdi olarak kullanılan ara dosyasını oluşturmalısınız 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);
}

Umarım yardımcı olur.


baos.toByteArray (), System.arraycopy ile bir kopya oluşturur. Mikeho'ya developer.classpath.org/doc/java/io/… 'ı
Mitja Gustin

20

Aralarında arabelleğe alınacak bir ara sınıfa ihtiyacınız olacak. Her InputStream.read(byte[]...)çağrıldığında, arabelleğe alma sınıfı, iletilen bayt dizisini, iletilen bir sonraki yığınla dolduracaktır OutputStream.write(byte[]...). Parçaların boyutları aynı olmayabileceğinden, adaptör sınıfının, okuma arabelleğini dolduracak ve / veya herhangi bir tampon taşmasını depolayabilecek kadar belirli bir miktar depolaması gerekecektir.

Bu makalede, bu soruna birkaç farklı yaklaşımın güzel bir dökümü var:

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


1
teşekkürler mckamey, Dairesel Tamponlar dayalı yöntem tam olarak ihtiyacım olan şey!
Hui Wang

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

2
toByteArray()Yöntem gövdesi return Arrays.copyOf(buf, count);yeni bir dizi döndüren böyle olduğu için bunu kullanmamalısınız .
Kök G


9

Ben bir ByteArrayOutputStreama dönüştürmek ile aynı sorunla karşılaştı ve iç tampon ile başlatılan bir döndürmek ByteArrayInputStreamtüretilmiş bir sınıf kullanarak çözüldü . Bu şekilde ek bellek kullanılmaz ve 'dönüşüm' çok hızlı olur: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'a koydum: https://github.com/nickrussler/ByteArrayInOutStream


içerik arabelleğe sığmazsa ne olur?
Vadimo

O zaman ilk olarak bir ByteArrayInputStream kullanmamalısınız.
Nick Russler

Bu çözüm bellekte tüm baytlara sahip olacaktır. Küçük dosyalar için bu iyi olacak, ancak ByteArrayOutput Stream
Vadimo'da

1
Eğer demek istediğin toByteArray bu dahili tampon benim yaklaşım olarak çok belleğe iki kat alacağını, hangi kopyalanacak neden olur. Düzenleme: Ah anlıyorum, küçük dosyalar için bu tabii ki çalışır ..
Nick Russler

Zaman kaybı. ByteArrayOutputStream, içeriği başka bir çıkış akışına aktarmak için bir writeTo yöntemine sahip
Tony BenBrahim

3

İo-extras kitaplığı yararlı olabilir. Örneğin bir gzip istiyorsanız InputStreamkullanarak GZIPOutputStreamve bunun gerçekleşmesi istediğiniz zaman uyumlu (8192 varsayılan tampon boyutunu kullanarak):

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

Kütüphane% 100 birim test kapsamına sahiptir (elbette buna değer!) Ve Maven Central'dadır. Maven bağımlılığı:

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

Daha sonraki bir sürümü kontrol ettiğinizden emin olun.


0

Benim açımdan, java.io.PipedInputStream / java.io.PipedOutputStream dikkate alınması gereken en iyi seçenektir. Bazı durumlarda ByteArrayInputStream / ByteArrayOutputStream öğesini kullanmak isteyebilirsiniz. Sorun, ByteArrayOutputStream öğesini bir ByteArrayInputStream öğesine dönüştürmek için arabelleği çoğaltmanız gerektiğidir. Ayrıca ByteArrayOutpuStream / ByteArrayInputStream 2GB ile sınırlıdır. İşte ByteArrayOutputStream / ByteArrayInputStream sınırlamalarını atlamak için yazdığım bir OutpuStream / InputStream uygulaması (Scala kodu, ancak java geliştiricileri için kolayca anlaşılabilir):

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

Kullanımı kolay, tampon çoğaltma yok, 2GB bellek sınırı yok

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

Bir InputStream'den OutputStream yapmak istiyorsanız, temel bir sorun vardır. OutputStream'e yazma yöntemi yapılana kadar engeller. Böylece sonuç yazma yöntemi tamamlandığında kullanılabilir. Bunun 2 sonucu vardır:

  1. Yalnızca bir iş parçacığı kullanırsanız, her şey yazılana kadar beklemeniz gerekir (bu nedenle akışın verilerini bellekte veya diskte saklamanız gerekir).
  2. Veri bitmeden önce erişmek istiyorsanız, ikinci bir iş parçacığına ihtiyacınız vardır.

Varyant 1, bayt dizileri kullanılarak uygulanabilir veya dosyalanabilir. Varyant 1, pipetler kullanılarak uygulanabilir (doğrudan veya ekstra soyutlama ile - örn. RingBuffer veya diğer yorumdaki google lib).

Gerçekten de standart java ile sorunu çözmenin başka bir yolu yoktur. Her çözüm bunlardan birinin bir uygulamasıdır.

"Devam" adı verilen bir kavram vardır ( ayrıntılar için bkz. Wikipedia ). Bu durumda temel olarak bu şu anlama gelir:

  • belirli miktarda veri bekleyen özel bir çıktı akışı var
  • Eğer miktara ulaşılırsa, akış, özel bir giriş akışı olan muadili için kontrol sağlar
  • giriş akışı okunana kadar veri miktarını sağlar, bundan sonra kontrolü çıkış akışına geçirir

Bazı dillerde bu kavram yerleşik olsa da, java için biraz "sihir" gerekir. Örneğin, java gibi apache uygulamalarından "commons-javaflow". Dezavantajı, bunun derleme sırasında bazı özel bayt kodu değişiklikleri gerektirmesidir. Bu nedenle, özel komut dosyaları içeren tüm öğeleri ekstra bir kitaplığa koymak mantıklı olacaktır.


-1

Eski gönderi ancak başkalarına yardımcı olabilir, Bu şekilde kullanın:

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

1
to String -> boyut sorunu
user1594895

Ayrıca, toString().getBytes()bir akışı * çağırmak akışın içeriğini döndürmez.
Maarten Bodewes

-1

Bir OutputStream öğesini bir InputStream öğesine dönüştüremeseniz de, java, PipedOutputStream ve PipedInputStream öğelerini kullanarak, ilişkili PipedInputStream aracılığıyla kullanılabilir olması için bir PipedOutputStream öğesine yazılan verilere sahip olabileceğiniz bir yol sağlar.
Bazen bir OutputStream örneği yerine bir InputStream örneğinin geçirilmesini gerektiren üçüncü taraf kitaplıklarıyla uğraşırken benzer bir durumla karşılaştım.
Bu sorunu düzeltmenin yolu PipedInputStream ve PipedOutputStream kullanmaktır.
Bu arada kullanmak zor ve istediğiniz şeyi elde etmek için çoklu kullanım kullanmanız gerekir. Kısa süre önce github'da kullanabileceğiniz bir uygulama yayınladım.
İşte bağlantı . Nasıl kullanılacağını anlamak için wiki'den geçebilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.