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


105

我最近看到了用于读取 InputStream在Kotlin中入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

注意: 这个问题是作者故意写和回答的(“ 自我回答的问题”),因此对常见Kotlin主题的惯用答案出现在SO中。

Answers:


216

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

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

警告:您可能会看到一些简短的示例:

val inputAsString = input.reader().readText() 

但是这些不会关闭流。确保检查API文档中所用的所有IO功能,以确保哪些关闭,哪些不关闭。通常,如果它们包含单词use(例如useLines()use()),则请在之后关闭流。有一个例外是File.readText()不同于Reader.readText()在于前者不留下任何东西打开,而后者确实需要一个明确的接近。

另请参阅: Kotlin IO相关扩展功能


1
对于您建议的扩展功能,我认为“ readText”比“ useText”更好。当我阅读“ useText”时,我期望一个类似use或的useLines函数对正在使用的东西执行一个块函数。例如inputStream.useText { text -> ... },另一方面,当我阅读“ readText”时,我期望有一个返回文本的函数:val inputAsString = inputStream.readText()
mfulton16年

是的,但是readText已经具有错误的含义,因此想要表明它更像是use这方面的功能。至少在此问答环节中。也许可以找到一个新的动词...
Jayson Minard

3
@ mfulton26 readTextAndClose()在此示例中,我避免与readText()不关闭的use模式以及需要lambda的模式发生冲突,因为我不打算引入新的stdlib函数,所以我只想强调使用扩展以节省未来的劳动力。
杰森·米纳德

@JaysonMinard为什么不标记为答案?虽然很棒:-)
piotrek1543 '16

2

将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)对于跨平台路径,应使用Paths.get()method。2)对于流-尝试资源功能(在kotlin中:.use {})
Evgeny Lebedev
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.