Kotlin InputStream to String (KISS)

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() 

Post a Comment

Previous Next

نموذج الاتصال