J'ai récemment vu un code permettant de lire le contenu complet d'un InputStream
dans une chaîne de Kotlin, tel que:
// input is of type InputStream
val baos = ByteArrayOutputStream()
input.use { it.copyTo(baos) }
val inputAsString = baos.toString()
Et aussi:
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()
}
Et même cela semble plus lisse puisqu'il ferme automatiquement le InputStream
:
val inputString = BufferedReader(InputStreamReader(input)).useLines { lines ->
val results = StringBuilder()
lines.forEach { results.append(it) }
results.toString()
}
Ou légère variation sur celui-là:
val results = StringBuilder()
BufferedReader(InputStreamReader(input)).forEachLine { results.append(it) }
val resultsAsString = results.toString()
Puis ce truc fonctionnel de pli:
val inputString = input.bufferedReader().useLines { lines ->
lines.fold(StringBuilder()) { buff, line -> buff.append(line) }.toString()
}
Ou une variante mauvaise qui ne ferme pas la InputStream
:
val inputString = BufferedReader(InputStreamReader(input))
.lineSequence()
.fold(StringBuilder()) { buff, line -> buff.append(line) }
.toString()
Mais ils sont tous maladroits et je continue à trouver des versions plus récentes et différentes de la même chose ... et certaines d’entre elles ne ferment jamais la InputStream
. Qu'est-ce qu'une manière non-maladroite (idiomatique) de lire le InputStream
?
Remarque: cette question est intentionnellement écrite et répondue par l'auteur ( Self-Answered Questions ) , de sorte que les réponses idiomatiques aux questions fréquemment posées de Kotlin soient présentes dans SO.
Kotlin a une extension spécifique juste à cette fin.
Le plus simple:
val inputAsString = input.bufferedReader().use { it.readText() } // defaults to UTF-8
Et dans cet exemple, vous pouvez choisir entre bufferedReader()
ou simplement reader()
. L'appel à la fonction Closeable.use()
fermera automatiquement l'entrée à la fin de l'exécution du lambda.
Lectures supplémentaires:
Si vous faites beaucoup de ce genre de choses, vous pouvez écrire ceci comme une fonction d'extension:
fun InputStream.readTextAndClose(charset: Charset = Charsets.UTF_8): String {
return this.bufferedReader(charset).use { it.readText() }
}
Que vous pourriez alors appeler facilement comme:
val inputAsString = input.readTextAndClose() // defaults to UTF-8
Par ailleurs, toutes les fonctions d’extension Kotlin nécessitant de connaître le charset
sont déjà définies par défaut sur UTF-8
. Ainsi, si vous avez besoin d’un codage différent, vous devez ajuster le code ci-dessus dans les appels pour inclure un codage pour reader(charset)
ou bufferedReader(charset)
.
Attention: Vous pouvez voir des exemples plus courts:
val inputAsString = input.reader().readText()
Mais ceux-ci ne ferment pas le flux . Assurez-vous de vérifier les documentation de l'API pour toutes les fonctions IO que vous utilisez pour vous assurer quelles sont celles qui sont fermées et celles qui ne le sont pas. Habituellement, s’ils incluent le mot use
(tel que useLines()
ou use()
), vous fermez le flux après. Une exception est que File.readText()
diffère de Reader.readText()
en ce que le premier ne laisse rien ouvert et que le second nécessite en effet une fermeture explicite.
Voir aussi: Kotlin IO fonctions d'extension associées
Un exemple qui lit le contenu d'un InputStream en chaîne
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)
}
Pour référence - fichier de lecture Kotlin