--- old/src/java.base/share/classes/java/io/InputStream.java 2018-01-24 11:34:00.000000000 -0800 +++ new/src/java.base/share/classes/java/io/InputStream.java 2018-01-24 11:34:00.000000000 -0800 @@ -63,7 +63,8 @@ * *

While the stream is open, the {@code available()}, {@code read()}, * {@code read(byte[])}, {@code read(byte[], int, int)}, - * {@code readAllBytes()}, {@code readNBytes()}, {@code skip()}, and + * {@code readAllBytes()}, {@code readNBytes(byte[], int, int)}, + * {@code readNBytes(int)}, {@code skip(long)}, and * {@code transferTo()} methods all behave as if end of stream has been * reached. After the stream has been closed, these methods all throw * {@code IOException}. @@ -123,6 +124,15 @@ } @Override + public byte[] readNBytes(int len) throws IOException { + if (len < 0) { + throw new IllegalArgumentException("len < 0"); + } + ensureOpen(); + return new byte[0]; + } + + @Override public long skip(long n) throws IOException { ensureOpen(); return 0L; @@ -233,8 +243,8 @@ * b 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 len 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. + * 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 b @@ -308,26 +318,85 @@ * It is strongly recommended that the stream be promptly closed if an I/O * error occurs. * + * @implSpec + * This method invokes {@link #readNBytes(int)} with a length of + * {@link Integer#MAX_VALUE}. + * * @return a byte array containing the bytes read from this input stream * @throws IOException if an I/O error occurs * @throws OutOfMemoryError if an array of the required size cannot be - * allocated. For example, if an array larger than {@code 2GB} would - * be required to store the bytes. + * allocated. * * @since 9 */ public byte[] readAllBytes() throws IOException { + return readNBytes(Integer.MAX_VALUE); + } + + /** + * Reads up to a specified number of bytes from the input stream. This + * method blocks until the requested number of bytes have been read, end + * of stream is detected, or an exception is thrown. This method does not + * close the input stream. + * + *

The length of the returned array equals the number of bytes read + * from the stream. If {@code len} is zero, then no bytes are read and + * an empty byte array is returned. Otherwise, up to {@code len} bytes + * are read from the stream. Fewer than {@code len} bytes may be read if + * end of stream is encountered. + * + *

When this stream reaches end of stream, further invocations of this + * method will return an empty byte array. + * + *

Note that this method is intended for simple cases where it is + * convenient to read the specified number of bytes into a byte array. The + * total amount of memory allocated by this method is proportional to the + * number of bytes read from the stream which is bounded by {@code len}. + * Therefore, the method may be safely called with very large values of + * {@code len} provided sufficient memory is available. + * + *

The behavior for the case where the input stream is asynchronously + * closed, or the thread interrupted during the read, is highly input + * stream specific, and therefore not specified. + * + *

If an I/O error occurs reading from the input stream, then it may do + * so after some, but not all, bytes have been read. Consequently the input + * stream may not be at end of stream and may be in an inconsistent state. + * It is strongly recommended that the stream be promptly closed if an I/O + * error occurs. + * + * @implNote + * The number of bytes allocated to read data from this stream and return + * the result is bounded by {@code 2*(long)len}, inclusive. + * + * @param len the maximum number of bytes to read + * @return a byte array containing the bytes read from this input stream + * @throws IllegalArgumentException if {@code length} is negative + * @throws IOException if an I/O error occurs + * @throws OutOfMemoryError if an array of the required size cannot be + * allocated. + * + * @since 11 + */ + public byte[] readNBytes(int len) throws IOException { + if (len < 0) { + throw new IllegalArgumentException("len < 0"); + } + List bufs = null; byte[] result = null; int total = 0; + int remaining = len; int n; do { - byte[] buf = new byte[DEFAULT_BUFFER_SIZE]; + byte[] buf = new byte[Math.min(remaining, DEFAULT_BUFFER_SIZE)]; int nread = 0; // read to EOF which may read more or less than buffer size - while ((n = read(buf, nread, buf.length - nread)) > 0) { + while ((n = read(buf, nread, + Math.min(buf.length - nread, remaining))) > 0) { nread += n; + remaining -= n; } if (nread > 0) { @@ -345,7 +414,9 @@ bufs.add(buf); } } - } while (n >= 0); // if the last call to read returned -1, then break + // if the last call to read returned -1 or the number of bytes + // requested have been read then break + } while (n >= 0 && remaining > 0); if (bufs == null) { if (result == null) { @@ -357,12 +428,12 @@ result = new byte[total]; int offset = 0; - int remaining = total; + remaining = total; for (byte[] b : bufs) { - int len = Math.min(b.length, remaining); - System.arraycopy(b, 0, result, offset, len); - offset += len; - remaining -= len; + int count = Math.min(b.length, remaining); + System.arraycopy(b, 0, result, offset, count); + offset += count; + remaining -= count; } return result;