src/share/classes/java/nio/file/Files.java

Print this page

        

@@ -23,14 +23,14 @@
  * questions.
  */
 
 package java.nio.file;
 
-import java.nio.ByteBuffer;
 import java.nio.file.attribute.*;
 import java.nio.file.spi.FileSystemProvider;
 import java.nio.file.spi.FileTypeDetector;
+import java.nio.channels.Channels;
 import java.nio.channels.FileChannel;
 import java.nio.channels.SeekableByteChannel;
 import java.io.Closeable;
 import java.io.InputStream;
 import java.io.OutputStream;

@@ -2963,11 +2963,67 @@
             return copy(in, out);
         }
     }
 
     /**
-     * Read all the bytes from a file. The method ensures that the file is
+     * 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;
+
+    /**
+     * Reads all the bytes from an input stream. Uses {@code initialSize} as a hint
+     * about how many bytes the stream will have.
+     *
+     * @param   source
+     *          the input stream to read from
+     * @param   initialSize
+     *          the initial size of the byte array to allocate
+     *
+     * @return  a byte array containing the bytes read from the file
+     *
+     * @throws  IOException
+     *          if an I/O error occurs reading from the stream
+     * @throws  OutOfMemoryError
+     *          if an array of the required size cannot be allocated
+     */
+    private static byte[] read(InputStream source, int initialSize)
+            throws IOException
+    {
+        int capacity = initialSize;
+        byte[] buf = new byte[capacity];
+        int nread = 0;
+        int n;
+        for (;;) {
+            // read to EOF which may read more or less than initialSize (eg: file
+            // is truncated while we are reading)
+            while ((n = source.read(buf, nread, capacity - nread)) > 0)
+                nread += n;
+
+            // if last call to source.read() returned -1, we are done
+            // otherwise, try to read one more byte; if that failed we're done too
+            if (n < 0 || (n = source.read()) < 0)
+                break;
+
+            // one more byte was read; need to allocate a larger buffer
+            if (capacity <= MAX_BUFFER_SIZE - capacity) {
+                capacity = Math.max(capacity << 1, BUFFER_SIZE);
+            } else {
+                if (capacity == MAX_BUFFER_SIZE)
+                    throw new OutOfMemoryError("Required array size too large");
+                capacity = MAX_BUFFER_SIZE;
+            }
+            buf = Arrays.copyOf(buf, capacity);
+            buf[nread++] = (byte)n;
+        }
+        return (capacity == nread) ? buf : Arrays.copyOf(buf, nread);
+    }
+
+    /**
+     * Reads all the bytes from a file. The method ensures that the file is
      * closed when all bytes have been read or an I/O error, or other runtime
      * exception, is thrown.
      *
      * <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

@@ -2987,26 +3043,17 @@
      *          In the case of the default provider, and a security manager is
      *          installed, the {@link SecurityManager#checkRead(String) checkRead}
      *          method is invoked to check read access to the file.
      */
     public static byte[] readAllBytes(Path path) throws IOException {
-        try (FileChannel fc = FileChannel.open(path)) {
+        try (FileChannel fc = FileChannel.open(path);
+             InputStream is = Channels.newInputStream(fc)) {
             long size = fc.size();
-            if (size > (long)Integer.MAX_VALUE)
+            if (size > (long)MAX_BUFFER_SIZE)
                 throw new OutOfMemoryError("Required array size too large");
 
-            byte[] arr = new byte[(int)size];
-            ByteBuffer bb = ByteBuffer.wrap(arr);
-            while (bb.hasRemaining()) {
-                if (fc.read(bb) < 0) {
-                    // truncated
-                    break;
-                }
-            }
-
-            int nread = bb.position();
-            return (nread == size) ? arr : Arrays.copyOf(arr, nread);
+            return read(is, (int)size);
         }
     }
 
     /**
      * Read all lines from a file. This method ensures that the file is