rahul
rahul

Reputation: 1290

Scala: InputStream to Array[Byte]

With Scala, what is the best way to read from an InputStream to a bytearray?

I can see that you can convert an InputStream to char array

Source.fromInputStream(is).toArray()

Upvotes: 44

Views: 39754

Answers (12)

R A
R A

Reputation: 295

Since JDK 9:

is.readAllBytes()

Upvotes: 1

Jitendra Nandre
Jitendra Nandre

Reputation: 161

We can do using Google API ByteStreams

com.google.common.io.ByteStreams

pass the stream to ByteStreams.toByteArray method for conversion

ByteStreams.toByteArray(stream)

Upvotes: 0

Eastsun
Eastsun

Reputation: 18859

How about:

Stream.continually(is.read).takeWhile(_ != -1).map(_.toByte).toArray

Update: use LazyList instead of Stream (since Stream is deprecated in Scala 3)

LazyList.continually(is.read).takeWhile(_ != -1).map(_.toByte).toArray

Upvotes: 49

Andriy Plokhotnyuk
Andriy Plokhotnyuk

Reputation: 7989

Just removed bottleneck in our server code by replacing

Stream.continually(request.getInputStream.read()).takeWhile(_ != -1).map(_.toByte).toArray

with

org.apache.commons.io.IOUtils.toByteArray(request.getInputStream)

Or in pure Scala:

def bytes(in: InputStream, initSize: Int = 8192): Array[Byte] = {
  var buf = new Array[Byte](initSize)
  val step = initSize
  var pos, n = 0
  while ({
    if (pos + step > buf.length) buf = util.Arrays.copyOf(buf, buf.length << 1)
    n = in.read(buf, pos, step)
    n != -1
  }) pos += n
  if (pos != buf.length) buf = util.Arrays.copyOf(buf, pos)
  buf
}

Do not forget to close an opened input stream in any case:

val in = request.getInputStream
try bytes(in) finally in.close()

Upvotes: 47

Andriy Onyshchuk
Andriy Onyshchuk

Reputation: 91

How about buffered version of solution based on streams plus ByteArraOutputStream to minimize boilerplate around final array growing?

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
}

Upvotes: 2

pathikrit
pathikrit

Reputation: 33409

With better-files, you can simply do is.bytes

Upvotes: 7

Chris Martin
Chris Martin

Reputation: 30736

Here's an approach using 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)

Upvotes: 1

TimT
TimT

Reputation: 1684

Source.fromInputStream(is).map(_.toByte).toArray

Upvotes: 3

Kevin Wright
Kevin Wright

Reputation: 49695

In a similar vein to Eastsun's answer... I started this as a comment, but it ended up getting just a bit to long!

I'd caution against using Stream, if holding a reference to the head element then streams can easily consume a lot of memory.

Given that you're only going to read in the file once, then Iterator is a much better choice:

def inputStreamToByteArray(is: InputStream): Array[Byte] =
  Iterator continually is.read takeWhile (-1 !=) map (_.toByte) toArray

Upvotes: 20

Wilfred Springer
Wilfred Springer

Reputation: 10927

With Scala IO, this should work:

def inputStreamToByteArray(is: InputStream): Array[Byte] = 
   Resource.fromInputStream(in).byteArray

Upvotes: 11

Y.H Wong
Y.H Wong

Reputation: 7244

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
}

Upvotes: -1

psp
psp

Reputation: 12158

import scala.tools.nsc.io.Streamable
Streamable.bytes(is)

Don't remember how recent that is: probably measured in days. Going back to 2.8, it's more like

new Streamable.Bytes { def inputStream() = is } toByteArray

Upvotes: 14

Related Questions