aboutsummaryrefslogtreecommitdiff
path: root/src/share/classes/sun/misc/IOUtils.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/share/classes/sun/misc/IOUtils.java')
-rw-r--r--src/share/classes/sun/misc/IOUtils.java291
1 files changed, 253 insertions, 38 deletions
diff --git a/src/share/classes/sun/misc/IOUtils.java b/src/share/classes/sun/misc/IOUtils.java
index 67079b9a67..5e6c79cb64 100644
--- a/src/share/classes/sun/misc/IOUtils.java
+++ b/src/share/classes/sun/misc/IOUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -32,67 +32,282 @@ package sun.misc;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
+
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
public class IOUtils {
+ private static final int DEFAULT_BUFFER_SIZE = 8192;
+
/**
- * Read up to {@code length} of bytes from {@code in}
- * until EOF is detected.
+ * The maximum size of array to allocate.
+ * Some VMs reserve some header words in an array.
+ * Attempts to allocate larger arrays may result in
+ * OutOfMemoryError: Requested array size exceeds VM limit
+ */
+ private static final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
+
+ /**
+ * Read exactly {@code length} of bytes from {@code in}.
+ *
+ * <p> Note that this method is safe to be called with unknown large
+ * {@code length} argument. The memory used is proportional to the
+ * actual bytes available. An exception is thrown if there are not
+ * enough bytes in the stream.
+ *
* @param is input stream, must not be null
- * @param length number of bytes to read, -1 or Integer.MAX_VALUE means
- * read as much as possible
- * @param readAll if true, an EOFException will be thrown if not enough
- * bytes are read. Ignored when length is -1 or Integer.MAX_VALUE
+ * @param length number of bytes to read
* @return bytes read
- * @throws IOException Any IO error or a premature EOF is detected
+ * @throws EOFException if there are not enough bytes in the stream
+ * @throws IOException if an I/O error occurs or {@code length} is negative
+ * @throws OutOfMemoryError if an array of the required size cannot be
+ * allocated.
*/
- public static byte[] readFully(InputStream is, int length, boolean readAll)
+ public static byte[] readExactlyNBytes(InputStream is, int length)
throws IOException {
- byte[] output = {};
- if (length == -1) length = Integer.MAX_VALUE;
- int pos = 0;
- while (pos < length) {
- int bytesToRead;
- if (pos >= output.length) { // Only expand when there's no room
- bytesToRead = Math.min(length - pos, output.length + 1024);
- if (output.length < pos + bytesToRead) {
- output = Arrays.copyOf(output, pos + bytesToRead);
- }
- } else {
- bytesToRead = output.length - pos;
+ if (length < 0) {
+ throw new IOException("length cannot be negative: " + length);
+ }
+ byte[] data = readNBytes(is, length);
+ if (data.length < length) {
+ throw new EOFException();
+ }
+ return data;
+ }
+
+ /**
+ * Reads all remaining bytes from the input stream. This method blocks until
+ * all remaining bytes have been read and end of stream is detected, or an
+ * exception is thrown. This method does not close the input stream.
+ *
+ * <p> When this stream reaches end of stream, further invocations of this
+ * method will return an empty byte array.
+ *
+ * <p> Note that this method is intended for simple cases where it is
+ * convenient to read all bytes into a byte array. It is not intended for
+ * reading input streams with large amounts of data.
+ *
+ * <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 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.
+ *
+ * @implSpec
+ * This method invokes {@link #readNBytes(int)} with a length of
+ * {@link Integer#MAX_VALUE}.
+ *
+ * @param is input stream, must not be null
+ * @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.
+ *
+ * @since 1.9
+ */
+ public static byte[] readAllBytes(InputStream is) throws IOException {
+ return readNBytes(is, 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.
+ *
+ * <p> 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.
+ *
+ * <p> When this stream reaches end of stream, further invocations of this
+ * method will return an empty byte array.
+ *
+ * <p> 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.
+ *
+ * <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 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 is input stream, must not be null
+ * @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 static byte[] readNBytes(InputStream is, int len) throws IOException {
+ if (len < 0) {
+ throw new IllegalArgumentException("len < 0");
+ }
+
+ List<byte[]> bufs = null;
+ byte[] result = null;
+ int total = 0;
+ int remaining = len;
+ int n;
+ do {
+ 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 = is.read(buf, nread,
+ Math.min(buf.length - nread, remaining))) > 0) {
+ nread += n;
+ remaining -= n;
}
- int cc = is.read(output, pos, bytesToRead);
- if (cc < 0) {
- if (readAll && length != Integer.MAX_VALUE) {
- throw new EOFException("Detect premature EOF");
+
+ if (nread > 0) {
+ if (MAX_BUFFER_SIZE - total < nread) {
+ throw new OutOfMemoryError("Required array size too large");
+ }
+ total += nread;
+ if (result == null) {
+ result = buf;
} else {
- if (output.length != pos) {
- output = Arrays.copyOf(output, pos);
+ if (bufs == null) {
+ bufs = new ArrayList<>();
+ bufs.add(result);
}
- break;
+ bufs.add(buf);
}
}
- pos += cc;
+ // 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) {
+ return new byte[0];
+ }
+ return result.length == total ?
+ result : Arrays.copyOf(result, total);
+ }
+
+ result = new byte[total];
+ int offset = 0;
+ remaining = total;
+ for (byte[] b : bufs) {
+ int count = Math.min(b.length, remaining);
+ System.arraycopy(b, 0, result, offset, count);
+ offset += count;
+ remaining -= count;
+ }
+
+ return result;
+ }
+
+ /**
+ * Reads the requested number of 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> 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 is input stream, must not be null
+ * @param b the byte array 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 static int readNBytes(InputStream is, 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 = is.read(b, off + n, len - n);
+ if (count < 0)
+ break;
+ n += count;
}
- return output;
+ return n;
}
/**
- * Read {@code length} of bytes from {@code in}. An exception is
- * thrown if there are not enough bytes in the stream.
+ * Compatibility wrapper for third party users of
+ * {@code sun.misc.IOUtils.readFully} following its
+ * removal in JDK-8231139.
+ *
+ * Read up to {@code length} of bytes from {@code in}
+ * until EOF is detected.
*
* @param is input stream, must not be null
- * @param length number of bytes to read, must not be negative
+ * @param length number of bytes to read
+ * @param readAll if true, an EOFException will be thrown if not enough
+ * bytes are read.
* @return bytes read
- * @throws IOException if any IO error or a premature EOF is detected, or
- * if {@code length} is negative since this length is usually also
- * read from {@code is}.
+ * @throws EOFException if there are not enough bytes in the stream
+ * @throws IOException if an I/O error occurs or {@code length} is negative
+ * @throws OutOfMemoryError if an array of the required size cannot be
+ * allocated.
*/
- public static byte[] readNBytes(InputStream is, int length) throws IOException {
+ public static byte[] readFully(InputStream is, int length, boolean readAll)
+ throws IOException {
if (length < 0) {
throw new IOException("length cannot be negative: " + length);
}
- return readFully(is, length, true);
+ if (readAll) {
+ return readExactlyNBytes(is, length);
+ } else {
+ return readNBytes(is, length);
+ }
}
}