RFR [9] Add blocking bulk read to java.io.InputStream
Chris Hegarty
chris.hegarty at oracle.com
Sat May 2 08:27:04 UTC 2015
Thanks for looking at this Roger.
On 1 May 2015, at 15:20, Roger Riggs <Roger.Riggs at oracle.com> wrote:
> Hi Chris,
>
> There is some duplication in the descriptions of the buffer contents; see below.
>
> On 5/1/2015 5:54 AM, Chris Hegarty wrote:
>> 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.
> This section duplicates the previous sentence and the following sentence.
I don’t see these as being duplicates.
The above states the case where some bytes have been read, while the paragraph below is always the case, regardless of whether any bytes are read. I see it as being explicit.
>> *
>> * <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.
> Duplicates previous paragraph.
Thanks, this was an editing issue. Removed.
As Alan has commented, another readAllBytes() returning a byte[] maybe useful too ( but a different use case ). Let’s park this momentarily, while I sketch up the readAllBytes variant, so we can ensure that the typical use cases have been addressed. Doing so may feedback into the spec of this method. I’ll push this latest draft into the sandbox so it is not lost.
-Chris.
> Each section of the buffer should be described only once.
>
> Regards, Roger
>
>> *
>> * <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 occur 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