在 Kotlin,如何将 InputStream 的全部内容读入 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的非笨拙(惯用)方法?

注: < em > 这个问题是作者(自我回答的问题)有意写作和回答的,因此常见的科特林问题的惯用答案在 SO 中出现。

78946 次浏览

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

但这些 不要关闭小溪。确保你检查的 所有 IO 函数的 API 文档你使用,以确保哪些关闭和哪些没有。通常,如果它们包含单词 use(如 useLines()use()) ,它们会在后面关闭流。一个例外是,File.readText()不同于 Reader.readText(),因为前者没有留下任何空白,而后者确实需要一个明确的关闭。

另见: < a href = “ https://kotlinlang.org/api/update/jvm/stdlib/Kotlin.IO/index.html”rel = “ noReferrer”> Kotlin IO 相关扩展函数

将 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 阅读文件

[ 方法1 | 手动关闭流]

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
}

[ 方法2 | 自动关闭流]

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

当将 InputStream 转换为 string 时,快速解决方案工作得很好。

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