programing

OutputStream을 InputStream으로 변환하는 방법

goodsources 2022. 7. 18. 22:18
반응형

OutputStream을 InputStream으로 변환하는 방법

는 현재, 그 중의 모듈로부터는 「모듈」, 「모듈」, 「모듈」, 「모듈」로.OutputStream 두 "" " " " " " " " 을 받아들입니다. " " "InputStream어떻게 변환하는지 아세요?OutputStream로로 합니다.InputStream(반대가 아니라, 정말 이런 식으로) 이 두 부분을 연결할 수 있을까요?

고마워요.

링크나 기타 여러 가지가 있는 것 같습니다만, 파이프를 사용한 실제 코드는 없습니다.와 를 사용하는 장점은 추가 메모리 소비가 없다는 것입니다. ByteArrayOutputStream.toByteArray()는 원래 버퍼의 복사본을 반환합니다.즉, 메모리에 저장되어 있는 것이 무엇이든 2개의 버퍼 복사본이 있음을 의미합니다. 그,, an an an an an에 글을 .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파일에 쓰지 않는 한 일반적으로 사용할 수 있는 유일한 출력 스트림이기 때문입니다.움이이됐됐!이 방법의 장점은 별도의 스레드에 있기 때문에 병렬로 동작하기 때문에 입력 스트림을 소비하는 것은 모두 오래된 출력 스트림에서 스트리밍됩니다.버퍼를 작게 유지할 수 있고 지연 시간과 메모리 사용량이 줄어들기 때문에 유용합니다.

OutputStream데이터를 쓰는 곳입니다.이 " " " 를 하는 OutputStream 끝에 이 있을

InputStream한편, 에서는 이 스트림을 들을 필요가 있어 읽을 수 있는 데이터가 있음을 나타내고 있습니다.

이렇게 '어울리다', '어울리다'를 수 있습니다.InputStream OutputStream

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

어떤 사람이 열의를 합니다.copy()method from IOTils를 사용하면 됩니다.다른 길로 가는 건 말이 안 돼이게 말이 됐으면 좋겠다

갱신:

물론 생각할수록 이것이 실제로 어떤 요건인지 알 수 있습니다.는 이 에 몇 알고 있습니다.Piped입력/출력 스트림이지만 다른 가능성이 있습니다.

이 " "일 "ByteArrayOutputStream에는 항상 '만', '만', '만', '만', '만', '만', '만', '만', '만', '만', '만', '만', '만', '만', '만', '만', '만', '만', '만', '만', '만', '만', '만', '만', '만'만'만'만,toByteArray()이렇게 해서 입력 .ByteArrayInputStream 2개는 .이들 2개는 의사 스트림이며 기본적으로는 바이트 배열만 랩합니다.따라서 이런 식으로 개울을 이용하는 것은 기술적으로도 가능하지만, 내게는 여전히 매우 낯설다.

입력 스트림과 출력 스트림은 시작점과 끝점일 뿐이므로 해결책은 바이트 배열에 데이터를 임시로 저장하는 것입니다. 중간을 요.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);
}

도움이 됐으면 좋겠다.

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

이치노 ★★InputStream.read(byte[]...)호출되면 에 "Byte Array"에서 .OutputStream.write(byte[]...). 않을 수 를 가득 오버플로를 수 청크의 크기가 같지 않을 수 있으므로 어댑터 클래스는 읽기 버퍼를 가득 채우고 버퍼 오버플로를 저장할 수 있을 때까지 일정량을 저장해야 합니다.

이 문서에서는 이 문제에 대한 몇 가지 다른 접근법에 대해 자세히 설명합니다.

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

Easystream 오픈 소스 라이브러리는 OutputStream을 InputStream으로 직접 변환할 수 있습니다.http://io-tools.sourceforge.net/easystream/tutorial/tutorial.html

// create conversion
final OutputStreamToInputStream<Void> out = new OutputStreamToInputStream<Void>() {
    @Override
    protected Void doRead(final InputStream in) throws Exception {
           LibraryClass2.processDataFromInputStream(in);
           return null;
        }
    };
try {   
     LibraryClass1.writeDataToTheOutputStream(out);
} finally {
     // don't miss the close (or a thread would not terminate correctly).
     out.close();
}

기타 옵션도 일람표시됩니다.

  • 데이터를 메모리 버퍼(ByteArrayOutputStream)에 쓰고 byteArray를 가져와 ByteArrayInputStream으로 다시 읽습니다.데이터가 메모리에 확실히 들어가 있는 경우는, 이 방법이 최적입니다.
  • 데이터를 임시 파일에 복사한 후 다시 읽어 보십시오.
  • 파이프 사용: 메모리 사용량과 속도(멀티코어 프로세서를 최대한 활용할 수 있음)와 Sun이 제공하는 표준 솔루션 모두에 대해 최적의 접근 방식입니다.
  • easystream 라이브러리에서 InputStream FromOutputStream 및 OutputStreamToInputStream을 사용합니다.

하였습니다.ByteArrayOutputStream a까지ByteArrayInputStream '부터'에서 를 사용해서 요.ByteArrayOutputStream,, 이, 를 반환할 수 .ByteArrayInputStream됩니다.ByteArrayOutputStream이렇게 하면 추가 메모리가 사용되지 않고 '변환'이 매우 빠릅니다.

package info.whitebyte.utils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

/**
 * This class extends the ByteArrayOutputStream by 
 * providing a method that returns a new ByteArrayInputStream
 * which uses the internal byte array buffer. This buffer
 * is not copied, so no additional memory is used. After
 * creating the ByteArrayInputStream the instance of the
 * ByteArrayInOutStream can not be used anymore.
 * <p>
 * The ByteArrayInputStream can be retrieved using <code>getInputStream()</code>.
 * @author Nick Russler
 */
public class ByteArrayInOutStream extends ByteArrayOutputStream {
    /**
     * Creates a new ByteArrayInOutStream. The buffer capacity is
     * initially 32 bytes, though its size increases if necessary.
     */
    public ByteArrayInOutStream() {
        super();
    }

    /**
     * Creates a new ByteArrayInOutStream, with a buffer capacity of
     * the specified size, in bytes.
     *
     * @param   size   the initial size.
     * @exception  IllegalArgumentException if size is negative.
     */
    public ByteArrayInOutStream(int size) {
        super(size);
    }

    /**
     * Creates a new ByteArrayInputStream that uses the internal byte array buffer 
     * of this ByteArrayInOutStream instance as its buffer array. The initial value 
     * of pos is set to zero and the initial value of count is the number of bytes 
     * that can be read from the byte array. The buffer array is not copied. This 
     * instance of ByteArrayInOutStream can not be used anymore after calling this
     * method.
     * @return the ByteArrayInputStream instance
     */
    public ByteArrayInputStream getInputStream() {
        // create new ByteArrayInputStream that respects the current count
        ByteArrayInputStream in = new ByteArrayInputStream(this.buf, 0, this.count);

        // set the buffer of the ByteArrayOutputStream 
        // to null so it can't be altered anymore
        this.buf = null;

        return in;
    }
}

github에 올렸습니다.https://github.com/nickrussler/ByteArrayInOutStream

라이브러리 입출력가 유용할 수 있습니다.예를 들어, 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>

최신 버전이 있는지 확인하십시오.

제 관점에서는 java.io 입니다.Piped Input Stream/java.io.Piped Output Stream은 검토하기에 가장 좋은 옵션입니다.상황에 따라서는 ByteArrayInputStream/ByteArrayOutputStream을 사용할 수 있습니다.문제는 ByteArrayOutputStream을 ByteArrayInputStream으로 변환하기 위해 버퍼를 복제해야 한다는 것입니다.또한 ByteArrayOutpuStream/ByteArrayInputStream은 2GB로 제한됩니다.다음은 ByteArrayOutputStream/ByteArrayInputStream 제한을 우회하기 위해 작성한 OutpuStream/InputStream 구현입니다(Scala 코드는 Java Developper에서는 쉽게 이해할 수 있습니다).

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

InputStream에서 OutputStream을 만드는 경우 기본적으로 문제가 하나 있습니다.완료될 때까지 OutputStream에 쓰는 메서드.그래서 글쓰기 방법이 완성되면 결과를 볼 수 있습니다.여기에는 다음 2가지 결과가 있습니다.

  1. 스레드를 하나만 사용하는 경우 모든 내용이 기록될 때까지 기다려야 합니다(따라서 스트림의 데이터를 메모리 또는 디스크에 저장해야 함).
  2. 완료되기 전에 데이터에 액세스하려면 두 번째 스레드가 필요합니다.

Variant 1은 바이트 배열 또는 파일을 사용하여 구현할 수 있습니다.Variant 1은 pipie를 사용하여 구현할 수 있습니다(직접 또는 추가 추상화(예:Ring Buffer 또는 다른 코멘트의 Google lib).

실제로 표준 자바에서는 문제를 해결할 다른 방법이 없습니다.각 솔루션은 이들 중 하나를 구현한 것입니다.

"계속"이라는 개념이 있습니다(자세한 내용은 위키피디아 참조).이 경우 기본적으로 다음과 같은 의미가 있습니다.

  • 특정 양의 데이터를 기대하는 특별한 출력 스트림이 있습니다.
  • 암마운트에 도달하면 스트림은 특별한 입력 스트림인 상대 스트림을 제어합니다.
  • 입력 스트림은 데이터를 읽을 때까지 사용 가능한 데이터 양을 만들고, 그 후 제어권을 출력 스트림으로 되돌립니다.

일부 언어에는 이 개념이 내장되어 있지만 Java의 경우 "매직"이 필요합니다.예를 들어 Java용 Apache 구현의 "commons-javaflow"를 들 수 있습니다.단점은 빌드 시 특별한 바이트 코드 수정이 필요하다는 것입니다.따라서 커스텀 빌드 스크립트를 사용하여 모든 파일을 추가 라이브러리에 저장하는 것이 좋습니다.

오래된 게시물이지만 다른 사람에게 도움이 될 수 있습니다. 다음 방법을 사용하십시오.

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

OutputStream InputStream은 Java PipedOutputStream PipedInputStream을 사용합니다.
예전에 OutputStream 인스턴스가 아닌 InputStream 인스턴스를 전달해야 하는 서드파티 라이브러리를 다룰 때도 비슷한 상황에 직면했습니다.
「PipedInputStream」 「PipedOutputStream」 「PipedOutputStream」 「PipedOutputStream」 。
참고로 그것들은 사용하기 까다롭고 원하는 것을 얻기 위해 멀티스레딩을 사용해야 합니다.저는 최근에 당신이 사용할 수 있는 github에 대한 구현을 발표했습니다.
여기 링크가 있습니다. Wiki를 통해 사용 방법을 이해할 수 있습니다.

언급URL : https://stackoverflow.com/questions/5778658/how-to-convert-outputstream-to-inputstream

반응형