Manière idiomatique de convertir un InputStream en String dans Scala

111

J'ai une fonction pratique que j'ai utilisée en Java pour convertir un InputStream en String. Voici une traduction directe à Scala:

  def inputStreamToString(is: InputStream) = {
    val rd: BufferedReader = new BufferedReader(new InputStreamReader(is, "UTF-8")) 
    val builder = new StringBuilder()    
    try {
      var line = rd.readLine 
      while (line != null) { 
        builder.append(line + "\n")
        line = rd.readLine
      }
    } finally {
      rd.close
    }
    builder.toString
  }

Existe-t-il un moyen idiomatique de faire cela dans scala?

bballant
la source

Réponses:

197

Pour Scala> = 2.11

scala.io.Source.fromInputStream(is).mkString

Pour Scala <2.11:

scala.io.Source.fromInputStream(is).getLines().mkString("\n")

fait à peu près la même chose. Vous ne savez pas pourquoi vous voulez obtenir des lignes, puis les recoller toutes ensemble, cependant. Si vous pouvez supposer que le flux n'est pas bloquant, vous pouvez simplement utiliser .available, lire le tout dans un tableau d'octets et créer une chaîne directement à partir de celui-ci.

Rex Kerr
la source
2
Une raison possible, que j'ai utilisée moi-même, est de normaliser les fins de ligne sur différents systèmes d'exploitation.
Kevin Wright
La réponse de Raam est également géniale (et légèrement plus concise), mais marquant Rex comme LA réponse, car elle ressemble plus spécifiquement à l'exemple. Recoller les lignes était spécifique à quelques cas, mais vous m'avez rappelé que j'ai utilisé ce code dans des endroits où ce n'est pas tout à fait approprié de le faire.
bballant
la solution n'est pas très sûre car elle utilise getLines (); que se passe-t-il si le flux d'entrée n'a pas de caractères de «nouvelle ligne»? puis tout bloque
Paul Sabou
Une très mauvaise solution. Que faire si le flux d'entrée contient des fins de ligne DOS (\ r \ n). Ceux-ci seraient supprimés par cette méthode. De plus, bien que mkString utilise un tampon, il serait certainement plus rapide de lire des blocs de caractères.
Dibbeke
1
@RexKerr Pouvez-vous nous signaler le "bug de performance" que vous avez mentionné dans votre réponse. J'ai testé les deux versions avec des cas de test de base et je n'ai rencontré aucun problème.
Sahil Sareen
74

Source.fromInputStream(is).mkString("") fera également l'acte .....

raam
la source
Bon point; la source crée quelque chose qui s'étend Iterator[Char].
Rex Kerr
8
Il est généralement bon de spécifier également le codage des caractères lors de ce genre de chose. À cette fin: Source.fromInputStream(is)(Codec.UTF8).mkString
Connor Doyle
C'est laconique, mais cela ne ferme pas le flux, contrairement au code Java d'origine.
Riche le
@Rich, fromInputStream()semble fermer le flux, au moins dans Scala 2.11.
jaco0646
2
@ jaco0646 - il ne ferme pas le flux. Je viens de tester. Voici le code de démonstration qui le prouve: gist.github.com/RichardBradley/bcd1a5e61fcc83e4e59f8b9b0bc2301c
Rich
13

Un moyen plus rapide de le faire:

    private def inputStreamToString(is: InputStream) = {
        val inputStreamReader = new InputStreamReader(is)
        val bufferedReader = new BufferedReader(inputStreamReader)
        Iterator continually bufferedReader.readLine takeWhile (_ != null) mkString
    }
Kamil Lelonek
la source
"plus rapide"? Mais cela m'a fourni la réponse sur la façon de le faire quand j'ai juste un Readeret pas un InputStream.
BeepDog
3
Sautez simplement la première ligne et passez inputStreamReaderà la méthode.
Kamil Lelonek
1
C'est potentiellement un ordre de grandeur plus rapide que scala.io.Source dans Scala 2.11.7. J'en ai écrit un benchmark très basique et la plupart du temps, il était environ 5% plus rapide pour les gros fichiers (le test était d'environ 35 Mo de fichier texte) jusqu'à 2800% plus rapide pour les petits fichiers (le test était d'environ 30 Ko) .
Colin Dean
2
Belle. J'ai eu du mal à trouver une solution élégante pour lire de grandes entrées Runtime.exec(). Cela cloue.
Pavel Lechev
Comment spécifier un jeu de caractères à utiliser?
wheeler