En Kotlin, ¿cómo leo todo el contenido de un InputStream en una cadena?
(2)
Kotlin tiene extensiones específicas solo para este propósito.
Lo más simple:
val inputAsString = input.bufferedReader().use { it.readText() } // defaults to UTF-8
Y en este ejemplo, podría decidir entre
bufferedReader()
o solo
reader()
.
La llamada a la función
Closeable.use()
cerrará automáticamente la entrada al final de la ejecución de lambda.
Otras lecturas:
Si haces mucho este tipo de cosas, podrías escribir esto como una función de extensión:
fun InputStream.readTextAndClose(charset: Charset = Charsets.UTF_8): String {
return this.bufferedReader(charset).use { it.readText() }
}
Que luego podría llamar fácilmente como:
val inputAsString = input.readTextAndClose() // defaults to UTF-8
En una nota al margen, todas las funciones de extensión de Kotlin que requieren conocer el
UTF-8
charset
ya tienen el valor predeterminado
UTF-8
, por lo que si necesita una codificación diferente, debe ajustar el código anterior en las llamadas para incluir una codificación para el
reader(charset)
o
bufferedReader(charset)
Advertencia: puede ver ejemplos que son más cortos:
val inputAsString = input.reader().readText()
Pero estos
no cierran la corriente
.
Asegúrese de consultar la
documentación de
la
API para ver todas las funciones de E / S
que utiliza para asegurarse de cuáles se cierran y cuáles no.
Por lo general, si incluyen la palabra
use
(como
useLines()
o
use()
), cierra la secuencia después.
Una excepción es que
File.readText()
difiere de
Reader.readText()
en que el primero no deja nada abierto y el último requiere un cierre explícito.
Consulte también: Funciones de extensión relacionadas con Kotlin IO
Recientemente vi código para leer todo el contenido de un
InputStream
en una cadena en Kotlin, como:
// input is of type InputStream
val baos = ByteArrayOutputStream()
input.use { it.copyTo(baos) }
val inputAsString = baos.toString()
Y también:
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()
}
E incluso esto se ve más suave ya que cierra automáticamente el
InputStream
:
val inputString = BufferedReader(InputStreamReader(input)).useLines { lines ->
val results = StringBuilder()
lines.forEach { results.append(it) }
results.toString()
}
O una ligera variación en ese:
val results = StringBuilder()
BufferedReader(InputStreamReader(input)).forEachLine { results.append(it) }
val resultsAsString = results.toString()
Entonces, este doblez funcional:
val inputString = input.bufferedReader().useLines { lines ->
lines.fold(StringBuilder()) { buff, line -> buff.append(line) }.toString()
}
O una
mala
variación que no cierra
InputStream
:
val inputString = BufferedReader(InputStreamReader(input))
.lineSequence()
.fold(StringBuilder()) { buff, line -> buff.append(line) }
.toString()
Pero todos son torpes y sigo encontrando versiones más nuevas y diferentes de los mismos ... y algunos de ellos ni siquiera cierran el
InputStream
.
¿Cuál es una forma no torpe (idiomática) de leer
InputStream
?
Nota: esta pregunta está escrita y respondida intencionalmente por el autor ( Preguntas con respuesta propia ), de modo que las respuestas idiomáticas a los temas de Kotlin más frecuentes están presentes en SO.
Un ejemplo que lee el contenido de un InputStream en una cadena
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)
}
Para referencia - Kotlin Read File