I recently saw code to read the entire contents of an InputStream into a String in Kotlin, like so:
// input is of type InputStream
val baos = ByteArrayOutputStream()
input.use { it.copyTo(baos) }
val inputAsString = baos.toString()
or like this,
val reader = BufferedReader(InputStreamReader(input))
try {
val results = StringBuilder()
while (true) {
val line = reader.readLine()
if (line == null) break
results.append(line)
}
val inputAsString = results.toString()
} finally {
reader.close()
}
And this one looks even smoother because it closes automatically:
val inputString = BufferedReader(InputStreamReader(input)).useLines { lines ->
val results = StringBuilder()
lines.forEach { results.append(it) }
results.toString()
}
Or a slight variation,
val results = StringBuilder()
BufferedReader(InputStreamReader(input)).forEachLine { results.append(it) }
val resultsAsString = results.toString()
Then like the functionality of folding something:
val inputString = input.bufferedReader().useLines { lines ->
lines.fold(StringBuilder()) { buff, line -> buff.append(line) }.toString()
}
Or a bad variation that doesn't close InputStream
val inputString = BufferedReader(InputStreamReader(input))
.lineSequence()
.fold(StringBuilder()) { buff, line -> buff.append(line) }
.toString()
But they're all clunky and I keep finding newer and different versions of the same thing... and some of them never even close the InputStream. What's a non-clunky (idiomatic) way to read an InputStream?
Solution
Kotlin has a special extension just for this purpose.
val inputAsString = input.bufferedReader().use { it.readText() } // defaults to UTF-8
And in this example, you can decide between bufferedReader()
or only reader()
. The call to the function Closeable.use()
will automatically close the input at the end of the lambda execution.
Further reading:
If you do this kind of thing a lot, you can write this as an extension function:
fun InputStream.readTextAndClose(charset: Charset = Charsets.UTF_8): String {
return this.bufferedReader(charset).use { it.readText() }
}
Which you can then easily call as:
val inputAsString = input.readTextAndClose() // defaults to UTF-8
As a side note, all Kotlin extension functions that require knowing the charset already default to UTF-8, so if you need a different encoding, you'll need to adjust the above code in the call to include the encoding for reader(charset)
or bufferedReader(charset)
.
Warning: You may see a shorter example:
val inputAsString = input.reader().readText()