Подтвердить что ты не робот

В Kotlin, как я могу прочитать все содержимое InputStream в String?

Недавно я видел код для чтения всего содержимого InputStream в String в Kotlin, например:

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

Тогда эта функциональная складка thingy:

val inputString = input.bufferedReader().useLines { lines ->
    lines.fold(StringBuilder()) { buff, line -> buff.append(line) }.toString()
}

Или параметр bad, который не закрывает InputStream:

val inputString = BufferedReader(InputStreamReader(input))
        .lineSequence()
        .fold(StringBuilder()) { buff, line -> buff.append(line) }
        .toString()

Но все они неуклюжи, и я продолжаю находить новые и разные версии того же... и некоторые из них даже не закрывают InputStream. Что такое неудобный (идиоматический) способ читать InputStream?

Примечание: этот вопрос намеренно написан автором и автору (Автоответчик), так что идиоматические ответы обычно спросила темы Котлина в SO.

4b9b3361

Ответ 1

У Kotlin есть специальные расширения только для этой цели.

Самый простой:

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

И в этом примере вы можете выбрать между bufferedReader() или просто reader(). Вызов функции Closeable.use() автоматически закроет вход в конце выполнения лямбда.

Дальнейшее чтение:

Если вы так много делаете, вы можете написать это как функцию расширения:

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, по умолчанию имеют значение UTF-8, поэтому, если вам требуется другая кодировка, вам необходимо настроить код выше в вызовах, чтобы включить кодировку для reader(charset) или bufferedReader(charset).

Предупреждение: Вы можете увидеть примеры, которые короче:

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

Но эти не закрывают поток. Убедитесь, что вы проверяете документацию API для всех функций ввода-вывода, которые вы используете, чтобы убедиться, какие из них закрыты, а какие нет. Обычно, если они включают слово use (например, useLines() или use()), вы закрываете поток после. Исключением является то, что File.readText() отличается от Reader.readText() тем, что первое не оставляет ничего открытого и последний действительно требует явного закрытия.

См. также: Функции расширения, связанные с IO Kotlin

Ответ 2

Пример, который читает содержимое InputStream для строки

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