mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-19 14:55:17 +00:00
8020669: (fs) Files.readAllBytes() does not read any data when Files.size() is 0
Reviewed-by: alanb, chegar, martin, rriggs
This commit is contained in:
parent
e1b3c5b5ba
commit
ebe38d6cdc
@ -25,10 +25,10 @@
|
||||
|
||||
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;
|
||||
@ -2965,7 +2965,63 @@ public final class Files {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
@ -2989,22 +3045,13 @@ public final class Files {
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
*/
|
||||
|
||||
/* @test
|
||||
* @bug 7006126
|
||||
* @bug 7006126 8020669
|
||||
* @summary Unit test for methods for Files readAllBytes, readAllLines and
|
||||
* and write methods.
|
||||
*/
|
||||
@ -82,6 +82,16 @@ public class BytesAndLines {
|
||||
write(file, lines, Charset.defaultCharset(), opts);
|
||||
throw new RuntimeException("NullPointerException expected");
|
||||
} catch (NullPointerException ignore) { }
|
||||
|
||||
// read from procfs
|
||||
if (System.getProperty("os.name").equals("Linux")) {
|
||||
// Refer to the Linux proc(5) man page for details about /proc/self/stat file
|
||||
// procfs reports it to be zero sized, even though data can be read from it
|
||||
String statFile = "/proc/self/stat";
|
||||
Path pathStat = Paths.get(statFile);
|
||||
byte[] data = Files.readAllBytes(pathStat);
|
||||
assertTrue(data.length > 0, "Files.readAllBytes('" + statFile + "') failed to read");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -174,6 +184,16 @@ public class BytesAndLines {
|
||||
throw new RuntimeException("NullPointerException expected");
|
||||
} catch (NullPointerException ignore) { }
|
||||
|
||||
// read from procfs
|
||||
if (System.getProperty("os.name").equals("Linux")) {
|
||||
// Refer to the Linux proc(5) man page for details about /proc/self/status file
|
||||
// procfs reports this file to be zero sized, even though data can be read from it
|
||||
String statusFile = "/proc/self/status";
|
||||
Path pathStatus = Paths.get(statusFile);
|
||||
lines = Files.readAllLines(pathStatus, US_ASCII);
|
||||
assertTrue(lines.size() > 0, "Files.readAllLines('" + pathStatus + "') failed to read");
|
||||
}
|
||||
|
||||
} finally {
|
||||
delete(tmpfile);
|
||||
}
|
||||
@ -242,7 +262,6 @@ public class BytesAndLines {
|
||||
} finally {
|
||||
delete(tmpfile);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void assertTrue(boolean expr, String errmsg) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user