Support File.readBytes when reported file length is less than actual

After reading 'length' bytes from a file, check if there's extra content
available and read it into a resizable buffer, then append it after
the first 'length' bytes.

#KT-33864
This commit is contained in:
Ilya Gorbunov
2019-09-25 03:53:54 +03:00
parent 3220101c7b
commit fe31509044
@@ -72,7 +72,31 @@ public fun File.readBytes(): ByteArray = inputStream().use { input ->
remaining -= read
offset += read
}
if (remaining == 0) result else result.copyOf(offset)
if (remaining > 0) return@use result.copyOf(offset)
val extraByte = input.read()
if (extraByte == -1) return@use result
// allocation estimate: (RS + DBS + max(ES, DBS + 1)) + (RS + ES),
// where RS = result.size, ES = extra.size, DBS = DEFAULT_BUFFER_SIZE
// when RS = 0, ES >> DBS => DBS + DBS + 1 + ES + ES = 2DBS + 2ES
// when RS >> ES, ES << DBS => RS + DBS + DBS+1 + RS + ES = 2RS + 2DBS + ES
val extra = ExposingBufferByteArrayOutputStream(DEFAULT_BUFFER_SIZE + 1)
extra.write(extraByte)
input.copyTo(extra)
val resultingSize = result.size + extra.size()
if (resultingSize < 0) throw OutOfMemoryError("File $this is too big to fit in memory.")
return@use extra.buffer.copyInto(
destination = result.copyOf(resultingSize),
destinationOffset = result.size,
startIndex = 0, endIndex = extra.size()
)
}
private class ExposingBufferByteArrayOutputStream(size: Int) : ByteArrayOutputStream(size) {
val buffer: ByteArray get() = buf
}
/**