lolski
lolski

Reputation: 17511

Reading from InputStream as an Iterator[Byte] or Array[Byte]

I am representing a data object as an Iterator[Byte], which is created from an InputStream instance.

The problem lies in that Byte is a signed integer from -128 to 127, while the read method in InputStream returns an unsigned integer from 0 to 255. This is in particular problematic since by semantics -1 should denote the end of an input stream.

What is the best way to alleviate the incompatibility between these two types? Is there an elegant way of converting between one to another? Or should I just use Int instead of Bytes, even though it feels less elegant?

def toByteIterator(in: InputStream): Iterator[Byte] = {
  Iterator.continually(in.read).takeWhile(-1 !=).map { elem =>
    convert // need to convert unsigned int to Byte here
  }
}

def toInputStream(_it: Iterator[Byte]): InputStream = {
  new InputStream {
    val (it, _) = _it.duplicate
    override def read(): Int = {
      if (it.hasNext) it.next() // need to convert Byte to unsigned int
      else -1
    }
  }
}

Upvotes: 2

Views: 2946

Answers (2)

Vladimir Matveev
Vladimir Matveev

Reputation: 128111

Yes, you can convert byte to int and vice versa easily.

First, int to byte can be converted with just toByte:

scala> 128.toByte
res0: Byte = -128

scala> 129.toByte
res1: Byte = -127

scala> 255.toByte
res2: Byte = -1

so your elem => convert could be just _.toByte.

Second, a signed byte can be converted to an unsigned int with a handy function in java.lang.Byte, called toUnsignedInt:

scala> java.lang.Byte.toUnsignedInt(-1)
res1: Int = 255

scala> java.lang.Byte.toUnsignedInt(-127)
res2: Int = 129

scala> java.lang.Byte.toUnsignedInt(-128)
res3: Int = 128

so you can write java.lang.Byte.toUnsignedInt(it.next()) in your second piece of code.

However, the last method is only available since Java 8. I don't know about its alternatives in older versions of Java, but its actual implementation is astonishingly simple:

public static int toUnsignedInt(byte x) {
    return ((int) x) & 0xff;
}

so all you need is just to write

it.next().toInt & 0xff

Upvotes: 1

Carlos Vilchez
Carlos Vilchez

Reputation: 2804

Unfortunately it is something related with a bad design of the class InputStream. If you use read() you will have that problem. You should use read(byte[]) instead. But as you say, you could also use Int. That is up to you.

Upvotes: 1

Related Questions