最近,我在Kotlin中看到了用于将InputStream的全部内容读取为String的代码,例如:

// input is of type InputStream
val baos = ByteArrayOutputStream()
input.use { it.copyTo(baos) }
val inputAsString = baos.toString()

并且:
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()
}

甚至看起来更平滑,因为它会自动关闭InputStream:
val inputString = BufferedReader(InputStreamReader(input)).useLines { lines ->
    val results = StringBuilder()
    lines.forEach { results.append(it) }
    results.toString()
}

或对此稍作改动:
val results = StringBuilder()
BufferedReader(InputStreamReader(input)).forEachLine { results.append(it) }
val resultsAsString = results.toString()

然后这个功能折叠很重要:
val inputString = input.bufferedReader().useLines { lines ->
    lines.fold(StringBuilder()) { buff, line -> buff.append(line) }.toString()
}

较差的变体形式,但没有关闭InputStream:
val inputString = BufferedReader(InputStreamReader(input))
        .lineSequence()
        .fold(StringBuilder()) { buff, line -> buff.append(line) }
        .toString()

但是它们都很笨拙,而且我一直在寻找相同的更新和不同版本...并且其中一些甚至从未关闭InputStream。什么是读取InputStream的非笨拙(惯用)方法?

注意:这个问题是作者故意写和回答的(Self-Answered Questions),因此SO中常见的Kotlin主题的惯用答案。

最佳答案

Kotlin为此有一个特定的扩展。

最简单的方法:

val inputAsString = input.bufferedReader().use { it.readText() }  // defaults to UTF-8

在此示例中,您可以在bufferedReader()reader()之间进行选择。调用函数 Closeable.use() 将在lambda执行结束时自动关闭输入。

进一步阅读:

如果您经常执行此类操作,则可以将其编写为扩展函数:
fun InputStream.readTextAndClose(charset: Charset = Charsets.UTF_8): String {
    return this.bufferedReader(charset).use { it.readText() }
}

然后您可以轻松地将其称为:
val inputAsString = input.readTextAndClose()  // defaults to UTF-8

附带说明一下,所有需要知道charset的Kotlin扩展功能已经默认为UTF-8,因此,如果您需要其他编码,则需要在调用中调整以上代码以包括reader(charset)bufferedReader(charset)的编码。

警告:您可能会看到简短的示例:
val inputAsString = input.reader().readText()

但是这些不会关闭流。确保检查使用的API documentation for all of the IO functions,以确保哪些关闭,哪些不关闭。通常,如果它们包含单词use(例如useLines()use()),请在之后关闭流。一个异常(exception)是 File.readText() Reader.readText() 的不同之处在于,前者没有打开任何东西,而后者确实需要显式关闭。

另请参见: Kotlin IO related extension functions

10-08 09:22
查看更多