Avoid allocating large buffers in File.writeText #KT-51058
Also fixes File.appendText and Path.write/appendText. Merge-request: KT-MR-12804 Merged-by: Abduqodiri Qurbonzoda <abduqodiri.qurbonzoda@jetbrains.com>
This commit is contained in:
committed by
Space Team
parent
54ab3d39db
commit
999b0f7099
@@ -5,12 +5,130 @@
|
||||
|
||||
package kotlin.jdk7.test
|
||||
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.nio.CharBuffer
|
||||
import java.nio.charset.Charset
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.StandardOpenOption
|
||||
import kotlin.io.path.*
|
||||
import kotlin.random.Random
|
||||
import kotlin.test.*
|
||||
|
||||
class PathReadWriteTest : AbstractPathTest() {
|
||||
|
||||
private fun String.encodeToByteArray(charset: Charset): ByteArray {
|
||||
val out = ByteArrayOutputStream()
|
||||
out.writer(charset).use { it.append(this) }
|
||||
return out.toByteArray()
|
||||
}
|
||||
|
||||
private val hexFormat = HexFormat {
|
||||
bytes.bytesPerLine = 32
|
||||
bytes.bytesPerGroup = 8
|
||||
}
|
||||
|
||||
private fun Path.testContentEquals(expectedContent: ByteArray, charset: Charset) {
|
||||
val expected = expectedContent.toHexString(hexFormat)
|
||||
val actualContent = readBytes()
|
||||
val actual = actualContent.toHexString(hexFormat)
|
||||
assertEquals(expected, actual, "$charset. Expected size is ${expectedContent.size}, actual size is ${actualContent.size}")
|
||||
}
|
||||
|
||||
private fun Path.testWriteText(text: String, charset: Charset) {
|
||||
// Path.writeText
|
||||
val encodedText = text.encodeToByteArray(charset)
|
||||
|
||||
writeText(text, charset)
|
||||
testContentEquals(encodedText, charset)
|
||||
|
||||
writeText(StringBuilder(text), charset)
|
||||
testContentEquals(encodedText, charset)
|
||||
|
||||
val position = 1.coerceAtMost(text.length)
|
||||
val limit = (text.length - 1).coerceAtLeast(position)
|
||||
val charBuffer = CharBuffer.wrap(text, position, limit)
|
||||
val encodedCharBuffer = text.substring(position, limit).encodeToByteArray(charset)
|
||||
|
||||
writeText(charBuffer, charset)
|
||||
testContentEquals(encodedCharBuffer, charset)
|
||||
assertEquals(position, charBuffer.position())
|
||||
assertEquals(limit, charBuffer.limit())
|
||||
assertEquals(text.length, charBuffer.capacity())
|
||||
|
||||
// Path.appendText
|
||||
val prefix = "_"
|
||||
val encodedPrefix = prefix.encodeToByteArray(charset)
|
||||
|
||||
writeText(prefix, charset)
|
||||
appendText(text, charset)
|
||||
testContentEquals(encodedPrefix + encodedText, charset)
|
||||
|
||||
writeText(prefix, charset)
|
||||
appendText(StringBuilder(text), charset)
|
||||
testContentEquals(encodedPrefix + encodedText, charset)
|
||||
|
||||
writeText(prefix, charset)
|
||||
appendText(charBuffer, charset)
|
||||
testContentEquals(encodedPrefix + encodedCharBuffer, charset)
|
||||
assertEquals(position, charBuffer.position())
|
||||
assertEquals(limit, charBuffer.limit())
|
||||
assertEquals(text.length, charBuffer.capacity())
|
||||
|
||||
// File.writeText
|
||||
toFile().writeText(text, charset)
|
||||
testContentEquals(encodedText, charset)
|
||||
|
||||
// File.appendText
|
||||
toFile().writeText(prefix, charset)
|
||||
toFile().appendText(text, charset)
|
||||
testContentEquals(encodedPrefix + encodedText, charset)
|
||||
}
|
||||
|
||||
@Test fun writeText() {
|
||||
val charsets = listOf(
|
||||
Charsets.UTF_8,
|
||||
Charsets.UTF_16,
|
||||
Charsets.UTF_32,
|
||||
Charsets.ISO_8859_1,
|
||||
Charsets.US_ASCII,
|
||||
)
|
||||
|
||||
val highSurrogate = Char.MIN_HIGH_SURROGATE
|
||||
val lowSurrogate = Char.MIN_LOW_SURROGATE
|
||||
|
||||
val smallString = "Hello"
|
||||
|
||||
val chunkSize = DEFAULT_BUFFER_SIZE
|
||||
val string = "k".repeat(chunkSize - 1)
|
||||
|
||||
val path = createTempFile().cleanup()
|
||||
|
||||
for (charset in charsets) {
|
||||
path.testWriteText("$highSurrogate", charset)
|
||||
|
||||
path.testWriteText("$lowSurrogate", charset)
|
||||
|
||||
path.testWriteText("$smallString$highSurrogate", charset)
|
||||
|
||||
path.testWriteText("$smallString$lowSurrogate", charset)
|
||||
|
||||
path.testWriteText("$string$highSurrogate", charset)
|
||||
|
||||
path.testWriteText("$string$lowSurrogate", charset)
|
||||
|
||||
path.testWriteText("$string$highSurrogate$lowSurrogate$string", charset)
|
||||
|
||||
path.testWriteText("$string$lowSurrogate$highSurrogate$string", charset)
|
||||
|
||||
path.testWriteText(
|
||||
"$string$highSurrogate$lowSurrogate${string.substring(2)}$highSurrogate$lowSurrogate",
|
||||
charset
|
||||
)
|
||||
|
||||
path.testWriteText("$string$lowSurrogate$highSurrogate$lowSurrogate$string", charset)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun appendText() {
|
||||
val file = createTempFile().cleanup()
|
||||
|
||||
Reference in New Issue
Block a user