2016-09-14 7 views
33

Я недавно видел код для чтения всего содержимого InputStream в строку в Котлин, такие как:В 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() 
} 

И даже это, что выглядит более гладкой, так как он автоматически -closes the 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.

ответ

75

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 documentation for all of the IO functions, который вы используете, чтобы убедиться, какие из них закрыты, а какие нет. Обычно, если они включают в себя слово use (например, useLines() или use()), вы закрываете поток после. Исключением является то, что File.readText() отличается от Reader.readText() тем, что первое не оставляет ничего открытого, а последнее действительно требует явного закрытия.

Смотрите также:Kotlin IO related extension functions

+1

Я думаю, что "READTEXT" был бы лучше имя чем «useText» для функции расширения, которую вы предлагаете. Когда я читаю «useText», я ожидаю такую ​​функцию, как 'use' или' useLines', которая выполняет блок-функцию на том, что «используется». например 'inputStream.useText {text -> ...}' С другой стороны, когда я читаю «readText», я ожидаю функцию, которая возвращает текст: 'val inputAsString = inputStream.readText()'. – mfulton26

+0

Правда, но readText уже имеет неправильный смысл, поэтому хотел означать, что это больше похоже на функции 'use' в этом отношении. по крайней мере, в контексте этого Q & A. возможно, новый глагол можно найти ... –

+2

@ mfulton26 Я пошел с 'readTextAndClose()' для этого примера, чтобы избежать конфликта с 'readText()' шаблонами не закрытия и шаблонами 'use', требующими лямбда, так как я «Я не пытаюсь ввести новую функцию stdlib. Я не хочу делать больше, чем говорить об использовании расширений, чтобы сохранить будущий труд. –

0

Пример, который считывает содержимое 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 Read File