2016-09-14 80 views
33

我最近看到的代碼讀取InputStream的全部內容複製到在科特林一個字符串,如:在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),從而使慣用解答常見科特林主題存在於SO。

回答

75

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以確定哪些關閉,哪些不關閉。通常,如果它們包含單詞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已經有錯誤的含義,所以想要表示它更像是在這方面的'使用'功能。至少在這個問答環境中。也許可以找到一個新的動詞...... –

+2

@ mfulton26爲了避免與'readText()'不關閉的模式衝突,並且''use''模式想要一個lambda,我使用'readTextAndClose我不想介紹一個新的stdlib函數,我不想做更多關於使用擴展來保存未來勞動力的觀點。 –

0

讀取的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