RFR [9] Add blocking bulk read to java.io.InputStream

Chris Hegarty chris.hegarty at oracle.com
Thu Apr 23 16:16:52 UTC 2015


On 23 Apr 2015, at 17:10, Peter Levart <peter.levart at gmail.com> wrote:

> On 04/23/2015 04:50 PM, Chris Hegarty wrote:
>> Peter,
>> 
>> Ah, good point. Do we really need a new Exception type for this, is this information really that useful? How can you recover?
>> 
>> What if this error condition was better cover in the API.
>> 
>> * <p> If an I/O error occurs reading from the input stream, then it may do
>> * so after some, but not all, bytes of {@code b} have been updated with
>> * data from the input stream. Consequently the input stream and {@code b}
>> * may be in an inconsistent state. It is strongly recommended that the
>> * stream be promptly closed if an I/O error occurs.
>> 
>> -Chris.
> 
> Right. Either that or special exception. Perhaps this utility method can be meant for those uses where the caller doesn't care and if she does, she must roll her own loop…

Right. I think simple is best here.

The pattern in the implementation occurs many times in real world code. This method is attempting to provide that to developers so that they don’t have to roll there own ( and risk getting it wrong ). But if you need something more sophisticated, then you can write it yourself.

-Chris. 

> Peter
> 
>> 
>> On 23 Apr 2015, at 15:20, Peter Levart <peter.levart at gmail.com> wrote:
>> 
>>> Hi Chris,
>>> 
>>> Currently InputStream guarantees that either some bytes are read *xor* EOF (-1) is returned *xor* IOException is thrown. Even with default implementation of read(byte[], int, int) which is implemented in terms of int read(). This new method can throw IOException after some bytes have successfully been read from stream and the caller does not get to know how many. Would something like the following make any more sense?
>>> 
>>>     public int readBytes(byte[] b, int off, int len) throws IOException {
>>>         Objects.requireNonNull(b);
>>>         if (off < 0 || len < 0 || len > b.length - off)
>>>             throw new IndexOutOfBoundsException();
>>>         int n = 0;
>>>         while (n < len) {
>>>             int count;
>>>             try {
>>>                 count = read(b, off + n, len - n);
>>>             } catch (IOException e) {
>>>                 if (n == 0) {
>>>                     throw e;
>>>                 } else {
>>>                     throw new IncompleteReadBytesException(e, n);
>>>                 }
>>>             }
>>>             if (count < 0)
>>>                 break;
>>>             n += count;
>>>         }
>>>         return n;
>>>     }
>>> 
>>>     /**
>>>      * Thrown from {@link #readBytes(byte[], int, int)} when at least one byte
>>>      * has successfully been read from stream into the byte buffer when IOException
>>>      * was thrown.
>>>      */
>>>     public static class IncompleteReadBytesException extends IOException {
>>>         private final int bytesRead;
>>>                  public IncompleteReadBytesException(IOException cause, int bytesRead) {
>>>             super(cause);
>>>             this.bytesRead = bytesRead;
>>>         }
>>> 
>>>         /**
>>>          * @return number of bytes read successfully from stream into byte array
>>>          *         before exception was thrown.
>>>          */
>>>         public int getBytesRead() {
>>>             return bytesRead;
>>>         }
>>>     }
>>> 
>>> 
>>> Regards, Peter
>>> 
>>> 
>>> On 04/23/2015 11:01 AM, Chris Hegarty wrote:
>>>> A while back when we added the long overdue java.io.InputStream.transferTo method, there was support for adding a blocking bulk read operation. This has been sitting in a branch in the sandbox since then. I would like to revive it with the intention of bringing it into 9. The motivation for this addition is provide library support for a common pattern found when reading from input streams.
>>>> 
>>>> /**
>>>>  * Reads some bytes from the input stream into the given byte array. This
>>>>  * method blocks until {@code len} bytes of input data have been read, or
>>>>  * end of stream is detected. The number of bytes actually read, possibly
>>>>  * zero, is returned. This method does not close the input stream.
>>>>  *
>>>>  * <p> In the case where end of stream is reached before {@code len} bytes
>>>>  * have been read, then the actual number of bytes read will be returned.
>>>>  * When this stream reaches end of stream, further invocations of this
>>>>  * method will return zero.
>>>>  *
>>>>  * <p> If {@code len} is zero, then no bytes are read and {@code 0} is
>>>>  * returned; otherwise, there is an attempt to read up to {@code len} bytes.
>>>>  *
>>>>  * <p> The first byte read is stored into element {@code b[off]}, the next
>>>>  * one in to {@code b[off+1]}, and so on. The number of bytes read is, at
>>>>  * most, equal to {@code len}. Let <i>k</i> be the number of bytes actually
>>>>  * read; these bytes will be stored in elements {@code b[off]} through
>>>>  * {@code b[off+}<i>k</i>{@code -1]}, leaving elements {@code b[off+}<i>k</i>
>>>>  * {@code ]} through {@code b[off+len-1]} unaffected.
>>>>  *
>>>>  * <p> In every case, elements {@code b[0]} through {@code b[off]} and
>>>>  * elements{@code b[off+len]} through {@code b[b.length-1]} are unaffected.
>>>>  *
>>>>  * <p> The behavior for the case where the input stream is <i>asynchronously
>>>>  * closed</i>, or the thread interrupted during the read, is highly input
>>>>  * stream specific, and therefore not specified.
>>>>  *
>>>>  * <p> If an I/O error occurs reading from the input stream, then it may do
>>>>  * so after some bytes have been read. Consequently the input stream may be
>>>>  * in an inconsistent state. It is strongly recommended that the stream be
>>>>  * promptly closed if an I/O error occurs.
>>>>  *
>>>>  * @param  b the buffer into which the data is read
>>>>  * @param  off the start offset in {@code b} at which the data is written
>>>>  * @param  len the maximum number of bytes to read
>>>>  * @return the actual number of bytes read into the buffer
>>>>  * @throws IOException if an I/O error occurs
>>>>  * @throws NullPointerException if {@code b} is {@code null}
>>>>  * @throws IndexOutOfBoundsException If {@code off} is negative, {@code len}
>>>>  *                is negative, or {@code len} is greater than {@code b.length - off}
>>>>  *
>>>>  * @since 1.9
>>>>  */
>>>> public int readBytes(byte[] b, int off, int len) throws IOException {
>>>>     Objects.requireNonNull(b);
>>>>     if (off < 0 || len < 0 || len > b.length - off)
>>>>         throw new IndexOutOfBoundsException();
>>>>     int n = 0;
>>>>     while (n < len) {
>>>>         int count = read(b, off + n, len - n);
>>>>         if (count < 0)
>>>>             break;
>>>>         n += count;
>>>>     }
>>>>     return n;
>>>> }
>>>> 
>>>> -Chris.
>>>> 
> 




More information about the core-libs-dev mailing list