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

Chris Hegarty chris.hegarty at oracle.com
Fri May 1 09:54:22 UTC 2015


This latest version addresses all comments so far:

/**
  * 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, end
  * of stream is detected, or an exception is thrown. 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 the case where {@code off > 0}, elements {@code b[0]} through
  * {@code b[off-1]} are unaffected. In every case, elements
  * {@code b[off+len]} through {@code b[b.length-1]} are unaffected.
  *
  * <p> In every case, elements {@code b[0]} through {@code b[off-1]} 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, 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.
  *
  * @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 readNBytes(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.

On 24/04/15 09:44, Chris Hegarty wrote:
> On 23 Apr 2015, at 22:24, Roger Riggs <Roger.Riggs at oracle.com> wrote:
>
>> Hi Pavel,
>>
>> On 4/23/2015 5:12 PM, Pavel Rappo wrote:
>>> Hey Roger,
>>>
>>> 1. Good catch! This thing also applies to java.io.InputStream.read(byte[], int, int):
>
> Yes, good catch indeed.
>
>>>       * <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.
>>>
>>> I suppose the javadoc for the method proposed by Chris has started its life as a
>>> copy of the javadoc read(byte[], int, int) which was assumed to be perfectly
>>> polished. Unfortunately it was a false assumption.
>> it happens...  many many people have read those descriptions  (or didn't because
>> it was too obvious or thought to be redundant).
>
> I propose this small amendment.
>
> * <p> In the case where {@code off > 0}, elements {@code b[0]} through
> * {@code b[off-1]} are unaffected. In every case, elements
> * {@code b[off+len]} through {@code b[b.length-1]} are unaffected.
>
>>>
>>> 2. About awkward sentences. This paragraph also has to be rephrased for the same reason:
>>>
>>>       * <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.
>>>
>>> If k == 0 then spec claims to store values in b[off]... b[off - 1].
>
> Reading the whole method description leads to be believe that 'k' cannot equal 0 at this point. The previous paragraph handles the case where len is 0. The previous paragraph to that handles the EOF case. This paragraph implicitly implies that k is greater than 0, “The first byte read”, and “the number of actual bytes read”, neither of which can be 0 at this point.
>
> I included below [*] the latest version of this method, including all comments so far.
>
>> If one concludes that's an empty interval then its ok; it just reads oddly and can
>> make the reader think its wrong.
>> In some cases it is easier if the upper bound is defined to be exclusive.
>> Then if lower == upper, its empty.
>>
>> If better language were constructed for the new method then perhaps it could
>> be worked back into methods with similar behavior later.  If the wording changes
>> in any significant way, the conformance team will have to go back and re-evaluate
>> it in detail to see if it really has changed.  So I'd leave it alone.
>>
>> Roger
>
> -Chris.
>
> [*]
>
> /**
>   * 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, end
>   * of stream is detected, or an exception is thrown. 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 the case where {@code off > 0}, elements {@code b[0]} through
>   * {@code b[off-1]} are unaffected. In every case, elements
>   * {@code b[off+len]} through {@code b[b.length-1]} are unaffected.
>   *
>   * <p> In every case, elements {@code b[0]} through {@code b[off-1]} 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, 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.
>   *
>   * @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 readNBytes(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;
> }
>



More information about the core-libs-dev mailing list