在 Kotlin 中,如何将 InputStream 的全部内容读入 String?

In Kotlin, how do I read the entire contents of an InputStream into a String?

我最近看到在 Kotlin 中将 InputStream 的全部内容读入字符串的代码,例如:

// 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)特意写下并回答的,以便对常见的 Kotlin 主题进行地道的回答存在于 SO 中。

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 you use to be sure which ones close and which do not. Usually, if they include the word use (such as useLines() or use()) they close the stream after. An exception is that File.readText() differs from Reader.readText(),因为前者不会打开任何东西,而后者确实需要明确关闭。

另请参阅: Kotlin IO related extension functions

将 InputStream 的内容读取到 String 的示例

import java.io.File
import java.io.InputStream
import java.nio.charset.Charset

fun main(args: Array<String>) {
    val file = File("input"+File.separator+"contents.txt")
    var ins:InputStream = file.inputStream()
    var content = ins.readBytes().toString(Charset.defaultCharset())
    println(content)
}

供参考 - Kotlin Read File

方法一 |手动关闭流

private fun getFileText(uri: Uri):String {
    val inputStream = contentResolver.openInputStream(uri)!!

    val bytes = inputStream.readBytes()        //see below

    val text = String(bytes, StandardCharsets.UTF_8)    //specify charset

    inputStream.close()

    return text
}

方法二 |自动关闭流

private fun getFileText(uri: Uri): String {
    return contentResolver.openInputStream(uri)!!.bufferedReader().use {it.readText() }
}

快速解决方案在将 InputStream 转换为字符串时效果很好。

val convertedInputStream = String(inputStream.readAllBytes(), StandardCharsets.UTF_8)