The beginning of a Scala “FileUtils” class

In production code I recommend that you use a good “Files” library like Apache Commons IO, but if you want to create your own Scala FileUtils class, here’s some source code that can help you get started.

First, here’s some code for the FileUtils class (an object, technically):

package io_examples.v1

import java.io.File
//import io_examples.common.Control.using
import scala.util.Try

object FileUtils {

    def readTextFileAsString(filename: String): Try[String] =
        Try {
            val lines = using(io.Source.fromFile(filename)) { source =>
                (for (line <- source.getLines) yield line).toList
            }
            lines.mkString("\n")
        }

    // TODO

    def copyFile(srcFile: File, destFile: File): Try[Boolean] = ???

    def readFileToByteArray(file: File): Try[Array[Byte]] = ???
    def readFileToString(file: File): Try[String] = ???
    def readFileToString(file: File, encoding: String): Try[String] = ???
    def readLines(file: File, encoding: String): Try[List[String]] = ???
    def sizeOf(file: File): Try[BigInt] = ???
    def sizeOfDirectory(directory: File): Try[BigInt] = ???

}

Here’s the using method that’s referenced in that code:

object Control {
    def using[A <: { def close(): Unit }, B](resource: A)(f: A => B): B =
        try {
            f(resource)
        } finally {
            resource.close()
        }
}

This code shows how you can use the readTextFileAsString method:

import scala.util.{Failure, Success}

object Driver extends App {

    val passwdFile = FileUtils.readTextFileAsString("/etc/passwd")
    passwdFile match {
        case Success(s) => println(s)
        case Failure(e) => println(e)
    }

}

I prefer the Try/Success/Failure approach for working with files, because it’s easy to generate exceptions with File I/O code, and I like to be able to access the reason for the failure, which you can get if you have the exception. Conversely, if you use Option/Some/None, you can’t get to the failure reason.

More Scala File utility methods

While I’m in the neighborhood, here are some more Scala file utility methods that I just found in another old project:

import java.io.File
import com.alvinalexander.annotations.impure

object FileUtils {

    val SLASH = System.getProperty("file.separator")
    
    /**
     * Get a recursive listing of all files underneath the given directory.
     * from stackoverflow.com/questions/2637643/how-do-i-list-all-files-in-a-subdirectory-in-scala
     */
    @impure def getRecursiveListOfFiles(dir: File): Seq[File] = {
        val fileArray = dir.listFiles
        fileArray ++ fileArray.filter(_.isDirectory).flatMap(getRecursiveListOfFiles)
    }
    
    @impure def getListOfFilesInDirectory(dirName: String): Seq[String] = {
        val dir = new File(dirName)
        dir.list
    }

    @impure def getListOfFilesInDirectoryAsOption (dirName: String): Option[Seq[String]] = {
        if (dirName==null || dirName.trim=="") {
            None
        } else {
            Some(getListOfFilesInDirectory(dirName))
        }
    }
    
}

If you want to use any of those methods, just delete the @impure annotation, it isn’t important, just something I was playing with back in the day.

Some older code file-reading code

While I’m in the neighborhood, here’s some older Scala file-reading code. This code doesn’t use Try, Option, or anything similar, so you won’t want to use it in production code without changing it:

def readFileToString(canonFilename: String): String = {
    val bufferedSource = Source.fromFile(canonFilename)
    val fileContents = bufferedSource.getLines.mkString
    bufferedSource.close
    fileContents
}

def readFileToSeq(canonFilename: String): Seq[String] = {
    val bufferedSource = Source.fromFile(canonFilename)
    val fileContents = bufferedSource.getLines.toList
    bufferedSource.close
    fileContents
}