Is there a good \"scala-esque\" (I guess I mean functional) way of recursively listing files in a directory? What about matching a particular pattern?
For example re
This incantation works for me:
def findFiles(dir: File, criterion: (File) => Boolean): Seq[File] = {
if (dir.isFile) Seq()
else {
val (files, dirs) = dir.listFiles.partition(_.isFile)
files.filter(criterion) ++ dirs.toSeq.map(findFiles(_, criterion)).foldLeft(Seq[File]())(_ ++ _)
}
}
I would prefer solution with Streams because you can iterate over infinite file system(Streams are lazy evaluated collections)
import scala.collection.JavaConversions._
def getFileTree(f: File): Stream[File] =
f #:: (if (f.isDirectory) f.listFiles().toStream.flatMap(getFileTree)
else Stream.empty)
Example for searching
getFileTree(new File("c:\\main_dir")).filter(_.getName.endsWith(".scala")).foreach(println)
for (file <- new File("c:\\").listFiles) { processFile(file) }
http://langref.org/scala+java/files
It seems nobody mentions the scala-io
library from scala-incubrator...
import scalax.file.Path
Path.fromString("c:\temp") ** "a*.foo"
Or with implicit
import scalax.file.ImplicitConversions.string2path
"c:\temp" ** "a*.foo"
Or if you want implicit
explicitly...
import scalax.file.Path
import scalax.file.ImplicitConversions.string2path
val dir: Path = "c:\temp"
dir ** "a*.foo"
Documentation is available here: http://jesseeichar.github.io/scala-io-doc/0.4.3/index.html#!/file/glob_based_path_sets
Why are you using Java's File instead of Scala's AbstractFile?
With Scala's AbstractFile, the iterator support allows writing a more concise version of James Moore's solution:
import scala.reflect.io.AbstractFile
def tree(root: AbstractFile, descendCheck: AbstractFile => Boolean = {_=>true}): Stream[AbstractFile] =
if (root == null || !root.exists) Stream.empty
else
(root.exists, root.isDirectory && descendCheck(root)) match {
case (false, _) => Stream.empty
case (true, true) => root #:: root.iterator.flatMap { tree(_, descendCheck) }.toStream
case (true, false) => Stream(root)
}
Here's a similar solution to Rex Kerr's, but incorporating a file filter:
import java.io.File
def findFiles(fileFilter: (File) => Boolean = (f) => true)(f: File): List[File] = {
val ss = f.list()
val list = if (ss == null) {
Nil
} else {
ss.toList.sorted
}
val visible = list.filter(_.charAt(0) != '.')
val these = visible.map(new File(f, _))
these.filter(fileFilter) ++ these.filter(_.isDirectory).flatMap(findFiles(fileFilter))
}
The method returns a List[File], which is slightly more convenient than Array[File]. It also ignores all directories that are hidden (ie. beginning with '.').
It's partially applied using a file filter of your choosing, for example:
val srcDir = new File( ... )
val htmlFiles = findFiles( _.getName endsWith ".html" )( srcDir )