Scala: How to search a directory tree with SimpleFileVisitor and Files.walkFileTree

As a brief note to self, if you ever want to write some code using Scala that recursively descends through a directory tree, here’s a solution that uses the Java SimpleFileVisitor and Files.walkFileTree method. First, here’s a skeleton class for the SimpleFileVisitor part of the solution:

import java.io._
import java.nio.file._
import java.nio.file.attribute._
import java.nio.file.FileVisitResult._
import java.nio.file.FileVisitOption._
import scala.io.Source

class Finder (filePattern: String, searchPattern: String)
extends SimpleFileVisitor[Path] {

    var pathMatcher: PathMatcher = null
    var numMatches = 0

    // note: "glob:" is part of the syntax
    // https://docs.oracle.com/javase/8/docs/api/java/nio/file/FileSystem.html#getPathMatcher-java.lang.String-
    pathMatcher = FileSystems.getDefault()
        .getPathMatcher("glob:" + filePattern)

    // add code here to work on files
    override def visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult = {
        find(file)
        return CONTINUE
    }

    // add code here to work on directories
    override def preVisitDirectory(dir: Path, attrs: BasicFileAttributes): FileVisitResult = {
        println(s"DIR: ${dir.toAbsolutePath()}")
        return CONTINUE
    }

    override def visitFileFailed(file: Path, ioe: IOException): FileVisitResult = {
        System.err.println(ioe)
        return CONTINUE
    }

    // compares the glob filePattern against the file or directory name
    def find(file: Path): Unit = {
        val name: Path = file.getFileName()
        // if the `name` matches what you’re looking for, do
        // what you want here with the file
        if (name != null && pathMatcher.matches(name)) {
            numMatches += 1
            val canonFilename = file.toAbsolutePath.toString
            println(s"match: $canonFilename")
        }
    }

    def done() = {
        println(s"Searched $numMatches $filePattern files.\n")
    }
    
}

In that class, just implement the visitFile, preVisitDirectory, and visitFileFailed methods as desired.

Next, here’s a Scala object that shows how to use that SimpleFileVisitor

import java.nio.file._

object FileFinder extends App {
    val finder = new Finder(
        "*.scala",
        "App"
    )
    Files.walkFileTree(
        Paths.get("/Users/al/Projects/Scala"),
        finder
    )
    finder.done()    
}

The combination of that class and object can be read as, “Search the /Users/al/Projects/Scala directory tree for all Scala files that contain the string App.” Notice how the Finder — which extends SimpleFileVisitor — is passed into the walkFileTree method of the Files class.

... this post is sponsored by my books ...
 

Summary

There’s more that can be said about how this code works, but for today, if you need a Java or Scala solution that lets you search a directory structure for files and directories, I hope this skeleton code is helpful.