Class ResizingPipedInputStream

  • All Implemented Interfaces:
    java.io.Closeable, java.lang.AutoCloseable

    public class ResizingPipedInputStream
    extends java.io.InputStream
    Manages a resizing buffer for production and consumption of data within a single thread. Buffered bytes may be consumed through the InputStream interface. This provides a few benefits over using a PipedOutputStream/PipedInputStream pair in a single thread:
    1. There is no risk of deadlock. Piped streams, which are intended for producing data in one thread and consuming it in another, will block on read when no data is available and block on write when the buffer is full. In a single-threaded context, avoiding deadlock on read requires checking that bytes are available before every read. Avoiding deadlock on write would require checking that the buffer is not full before every write, but there is no built-in, publicly-accessible way of doing this with a PipedInputStream/PipedOutputStream.
    2. The buffer can grow. Piped streams use a fixed-size buffer that causes blocking when full. If used in a single-thread, this serves as a hard limit on the amount of data that can be written without a matching read. This can require arbitrary limits on data size to be imposed by the application. The ResizingPipedInputStream imposes no such limitation, but optionally allows for a maximum buffer size to be configured to protect against unbounded growth.
    • Constructor Summary

      Constructors 
      Constructor Description
      ResizingPipedInputStream​(int initialBufferSize)
      Constructor.
    • Method Summary

      All Methods Instance Methods Concrete Methods 
      Modifier and Type Method Description
      int available()
      int capacity()  
      void copyTo​(java.io.OutputStream outputStream)
      Copies all of the available bytes in the buffer without changing the number of bytes available to subsequent reads.
      int read()
      int read​(byte[] b, int off, int len)
      void receive​(byte[] b)
      Buffers `b.length` additional bytes.
      void receive​(byte[] b, int off, int len)
      Buffers `len` additional bytes, growing the buffer if it is already full or if it would become full by writing `len` bytes.
      void receive​(int b)
      Buffers a single additional byte, growing the buffer if it is already full.
      int receive​(java.io.InputStream input, int len)
      Buffers up to `len` additional bytes, growing the buffer if it is already full or if it would become full by writing `len` bytes.
      long skip​(long n)
      Skips up to `n` buffered bytes.
      • Methods inherited from class java.io.InputStream

        close, mark, markSupported, nullInputStream, read, readAllBytes, readNBytes, readNBytes, reset, transferTo
      • Methods inherited from class java.lang.Object

        clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    • Constructor Detail

      • ResizingPipedInputStream

        public ResizingPipedInputStream​(int initialBufferSize)
        Constructor.
        Parameters:
        initialBufferSize - the initial size of the buffer. When full, the buffer will grow by this many bytes. The buffer always stores bytes contiguously, so growth requires allocation of a new buffer capable of holding the new capacity and copying of the existing bytes into the new buffer. As such, a size should be chosen carefully such that growth is expected to occur rarely, if ever.
    • Method Detail

      • receive

        public void receive​(int b)
        Buffers a single additional byte, growing the buffer if it is already full.
        Parameters:
        b - the byte to buffer.
      • receive

        public void receive​(byte[] b,
                            int off,
                            int len)
        Buffers `len` additional bytes, growing the buffer if it is already full or if it would become full by writing `len` bytes.
        Parameters:
        b - the bytes to buffer.
        off - the offset into `b` that points to the first byte to buffer.
        len - the number of bytes to buffer.
      • receive

        public void receive​(byte[] b)
        Buffers `b.length` additional bytes.
        Parameters:
        b - the bytes to buffer.
        See Also:
        receive(byte[], int, int)
      • receive

        public int receive​(java.io.InputStream input,
                           int len)
                    throws java.io.IOException
        Buffers up to `len` additional bytes, growing the buffer if it is already full or if it would become full by writing `len` bytes. This method will block if and only if the given `InputStream`'s InputStream.read(byte[], int, int) blocks when trying to read `len` bytes. If this is not desired, the caller should ensure that the given `InputStream` has at least `len` bytes available before calling this method or provide an InputStream implementation that does not block.
        Parameters:
        input - the source of the bytes.
        len - the number of bytes to attempt to write.
        Returns:
        the number of bytes actually written, which will only be less than `len` if InputStream.read(byte[], int, int) returns less than `len`.
        Throws:
        java.io.IOException - if thrown by the given `InputStream` during read, except for EOFException. If an EOFException is thrown by the `InputStream`, it will be caught and this method will return the number of bytes that were received before the exception was thrown.
      • read

        public int read​(byte[] b,
                        int off,
                        int len)

        NOTE: This method adheres to the documented behavior of InputStream.read(byte[], int, int) except that it never blocks. If a read is attempted before the first write, this method will return -1.

        Overrides:
        read in class java.io.InputStream
      • copyTo

        public void copyTo​(java.io.OutputStream outputStream)
                    throws java.io.IOException
        Copies all of the available bytes in the buffer without changing the number of bytes available to subsequent reads.
        Parameters:
        outputStream - stream to which the bytes will be copied.
        Throws:
        java.io.IOException - if thrown by OutputStream.write(byte[], int, int).
      • skip

        public long skip​(long n)
        Skips up to `n` buffered bytes. Less than `n` bytes will be skipped if less than `n` bytes are available in the buffer.
        Overrides:
        skip in class java.io.InputStream
        Parameters:
        n - the number of bytes to skip.
        Returns:
        the number of bytes actually skipped.
      • available

        public int available()

        NOTE: This method adheres to the documented behavior of InputStream.available() except that it always returns the exact number of bytes that are available in the buffer.

        Overrides:
        available in class java.io.InputStream
        Returns:
        the exact number of bytes available in the buffer.
      • read

        public int read()

        NOTE: This method adheres to the documented behavior of InputStream.read(byte[], int, int) except that it never blocks. If a read is attempted before the first write, this method will return -1.

        Specified by:
        read in class java.io.InputStream
      • capacity

        public int capacity()
        Returns:
        the capacity of the buffer, which is always less than or equal to 'maximumBufferSize'.