ICU-11341 better ICUBinary.getByteBufferFromInputStream(): minimize number of memory allocations, allocate available() bytes on good JDK, do not rely on available() for finding the end of the stream

X-SVN-Rev: 36681
This commit is contained in:
Markus Scherer 2014-10-20 20:45:22 +00:00
parent d302fddd6b
commit 299f24790f

View file

@ -519,32 +519,52 @@ public final class ICUBinary {
*/
public static ByteBuffer getByteBufferFromInputStream(InputStream is) throws IOException {
try {
// is.available() may return 0, or 1, or the total number of bytes in the stream,
// or some other number.
// Do not try to use is.available() == 0 to find the end of the stream!
byte[] bytes;
int avail = is.available();
byte[] bytes = new byte[avail];
readFully(is, bytes, 0, avail);
while((avail = is.available()) != 0) {
// TODO Java 6 replace new byte[] and arraycopy(): byte[] newBytes = Arrays.copyOf(bytes, bytes.length + avail);
byte[] newBytes = new byte[bytes.length + avail];
System.arraycopy(bytes, 0, newBytes, 0, bytes.length);
readFully(is, newBytes, bytes.length, avail);
bytes = newBytes;
if (avail > 32) {
// There are more bytes available than just the ICU data header length.
// With luck, it is the total number of bytes.
bytes = new byte[avail];
} else {
bytes = new byte[128]; // empty .res files are even smaller
}
return ByteBuffer.wrap(bytes);
// Call is.read(...) until one returns a negative value.
int length = 0;
for(;;) {
if (length < bytes.length) {
int numRead = is.read(bytes, length, bytes.length - length);
if (numRead < 0) {
break; // end of stream
}
length += numRead;
} else {
// See if we are at the end of the stream before we grow the array.
int nextByte = is.read();
if (nextByte < 0) {
break;
}
int capacity = 2 * bytes.length;
if (capacity < 128) {
capacity = 128;
} else if (capacity < 0x4000) {
capacity *= 2; // Grow faster until we reach 16kB.
}
// TODO Java 6 replace new byte[] and arraycopy(): bytes = Arrays.copyOf(bytes, capacity);
byte[] newBytes = new byte[capacity];
System.arraycopy(bytes, 0, newBytes, 0, length);
bytes = newBytes;
bytes[length++] = (byte) nextByte;
}
}
return ByteBuffer.wrap(bytes, 0, length);
} finally {
is.close();
}
}
private static void readFully(InputStream is, byte[] bytes, int offset, int avail)
throws IOException {
while (avail > 0) {
int numRead = is.read(bytes, offset, avail);
assert numRead > 0;
offset += numRead;
avail -= numRead;
}
}
/**
* Returns a VersionInfo for the bytes in the compact version integer.
*/