Avec Scala, quel est le meilleur moyen de lire un InputStream en un bytearray?
Je peux voir que vous pouvez convertir un InputStream en tableau de caractères
Source.fromInputStream(is).toArray()
Que diriez-vous:
Stream.continually(is.read).takeWhile(_ != -1).map(_.toByte).toArray
Nous venons de supprimer le goulot d’étranglement de notre code serveur en remplaçant
Stream.continually(request.getInputStream.read()).takeWhile(_ != -1).map(_.toByte).toArray
avec
org.Apache.commons.io.IOUtils.toByteArray(request.getInputStream)
Dans la même veine que la réponse d'Eastsun ... j'ai commencé par un commentaire, mais cela a été un peu long!
Je vous déconseille d'utiliser Stream
, si le fait de garder une référence à l'élément head puis les flux peuvent facilement consommer beaucoup de mémoire.
Étant donné que vous n'allez lire qu'une seule fois dans le fichier, alors Iterator
est un bien meilleur choix:
def inputStreamToByteArray(is: InputStream): Array[Byte] =
Iterator continually is.read takeWhile (-1 !=) map (_.toByte) toArray
import scala.tools.nsc.io.Streamable
Streamable.bytes(is)
Je ne me souviens pas à quel point c'est récent: probablement mesuré en jours. En revenant à 2.8, ça ressemble plus à
new Streamable.Bytes { def inputStream() = is } toByteArray
Avec Scala IO , cela devrait fonctionner:
def inputStreamToByteArray(is: InputStream): Array[Byte] =
Resource.fromInputStream(in).byteArray
Avec better-files , vous pouvez simplement faire is.bytes
Source.fromInputStream (is) .map (_. ToByte) .toArray
Que diriez-vous de la version tamponnée de la solution basée sur les flux plus ByteArraOutputStream afin de minimiser l’impact autour de la croissance de la matrice finale?
val EOF: Int = -1
def readBytes(is: InputStream, bufferSize: Int): Array[Byte] = {
val buf = Array.ofDim[Byte](bufferSize)
val out = new ByteArrayOutputStream(bufferSize)
Stream.continually(is.read(buf)) takeWhile { _ != EOF } foreach { n =>
out.write(buf, 0, n)
}
out.toByteArray
}
Voici une approche utilisant scalaz-stream:
import scalaz.concurrent.Task
import scalaz.stream._
import scodec.bits.ByteVector
def allBytesR(is: InputStream): Process[Task, ByteVector] =
io.chunkR(is).evalMap(_(4096)).reduce(_ ++ _).lastOr(ByteVector.empty)
Une alternative basée sur Scala 2.13
's new Seq::unfold
:
Seq.unfold(())(_ => Some(is.read.toByte, ()).filter(_._1 != -1)).toArray
et sa variante utilisant le filtrage par motif:
Seq.unfold(())(_ => is.read.toByte match { case -1 => None case b => Some(b, ()) }).toArray
def inputStreamToByteArray(is: InputStream): Array[Byte] = {
val buf = ListBuffer[Byte]()
var b = is.read()
while (b != -1) {
buf.append(b.byteValue)
b = is.read()
}
buf.toArray
}