From fe315090449a9d4fa10680a93f562c329eb6259b Mon Sep 17 00:00:00 2001 From: Ilya Gorbunov Date: Wed, 25 Sep 2019 03:53:54 +0300 Subject: [PATCH] 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 --- .../stdlib/jvm/src/kotlin/io/FileReadWrite.kt | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) 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 } /**