diff --git a/libraries/stdlib/jvm/src/kotlin/io/FileReadWrite.kt b/libraries/stdlib/jvm/src/kotlin/io/FileReadWrite.kt index b13c4d322a2..ce3f5190bb5 100644 --- a/libraries/stdlib/jvm/src/kotlin/io/FileReadWrite.kt +++ b/libraries/stdlib/jvm/src/kotlin/io/FileReadWrite.kt @@ -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 } /**