How to read and write binary files in Scala

This is an excerpt from the Scala Cookbook (partially modified for the internet). This is Recipe 12.3, “How to read and write binary files in Scala.”

Problem

You want to read data from a binary file or write data to a binary file.

Solution

Scala doesn’t offer any special conveniences for reading or writing binary files, so either use a) the Apache Commons IO library, or b) the Java FileInputStream and FileOutputStream classes. I’ll show those classes in this recipe.

To demonstrate those classes, the following code is a close Scala translation of the CopyBytes class in the Oracle Byte Streams tutorial:

import java.io._

object CopyBytes extends App {
    var in = None: Option[FileInputStream]
    var out = None: Option[FileOutputStream]
    try {
        in = Some(new FileInputStream("/tmp/Test.class"))
        out = Some(new FileOutputStream("/tmp/Test.class.copy"))
        var c = 0
        while ({c = in.get.read; c != −1}) {
            out.get.write(c)
        }
    } catch {
        case e: IOException => e.printStackTrace
    } finally {
        println("entered finally ...")
        if (in.isDefined) in.get.close
        if (out.isDefined) out.get.close
    }
}

In this code, in and out are populated in the try clause. It’s safe to call in.get and out.get in the while loop, because if an exception had occurred, flow control would have switched to the catch clause, and then the finally clause before leaving the method.

Normally I tell people that I think the get and isDefined methods on Option would be deprecated, but this is one of the few times where I think their use is acceptable and they lead to more readable code.

Another difference between this code and Oracle’s example is the while loop, which is slightly different in Scala. This change is required because a Java statement like c = in.read has a type of Unit in Scala, and will therefore never be equal to −1 (or any other value). There are several other ways to work around this difference — such as using a for-expression rather than a while loop — but this example shows a fairly direct translation.

See Also