如何列出scala子目录中的所有文件?

是否有一个很好的“scala-esque”(我想我的意思是function)的方式recursion列出目录中的文件? 匹配一个特定的模式呢?

例如recursion地在c:\temp匹配"a*.foo"所有文件。

Scala代码通常使用Java类来处理I / O,包括读取目录。 所以你必须做一些事情:

 import java.io.File def recursiveListFiles(f: File): Array[File] = { val these = f.listFiles these ++ these.filter(_.isDirectory).flatMap(recursiveListFiles) } 

你可以收集所有的文件,然后使用正则expression式进行过滤:

 myBigFileArray.filter(f => """.*\.html$""".r.findFirstIn(f.getName).isDefined) 

或者你可以将regex并入recursionsearch:

 import scala.util.matching.Regex def recursiveListFiles(f: File, r: Regex): Array[File] = { val these = f.listFiles val good = these.filter(f => r.findFirstIn(f.getName).isDefined) good ++ these.filter(_.isDirectory).flatMap(recursiveListFiles(_,r)) } 

我更喜欢Streams的解决scheme,因为你可以遍历无限的文件系统(Streams是延迟评估集合)

 import scala.collection.JavaConversions._ def getFileTree(f: File): Stream[File] = f #:: (if (f.isDirectory) f.listFiles().toStream.flatMap(getFileTree) else Stream.empty) 

search示例

 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

斯卡拉是一个多范式的语言。 迭代目录的一个好的“scala-esque”方法是重用现有的代码!

我会考虑使用commons-io迭代一个目录完全scala-esque的方式。 您可以使用一些隐式转换来使其更容易。 喜欢

 import org.apache.commons.io.filefilter.IOFileFilter implicit def newIOFileFilter (filter: File=>Boolean) = new IOFileFilter { def accept (file: File) = filter (file) def accept (dir: File, name: String) = filter (new java.io.File (dir, name)) } 

我喜欢yura的stream解决scheme,但它(和其他人)recursion到隐藏的目录。 我们也可以通过使用listFiles为非目录返回null的事实来简化。

 def tree(root: File, skipHidden: Boolean = false): Stream[File] = if (!root.exists || (skipHidden && root.isHidden)) Stream.empty else root #:: ( root.listFiles match { case null => Stream.empty case files => files.toStream.flatMap(tree(_, skipHidden)) }) 

现在我们可以列出文件

 tree(new File(".")).filter(f => f.isFile && f.getName.endsWith(".html")).foreach(println) 

或者实现整个stream以供后续处理

 tree(new File("dir"), true).toArray 

从Java 1.7开始,你应该使用java.nio。 它提供了接近本机的性能(java.io非常慢)并且有一些有用的帮助

但是Java 1.8正好引入了你正在寻找的东西:

 val dir = FileSystems.getDefault.getPath("/Volumes/F") java.nio.file.Files.walk(dir).iterator().asScala.filter(Files.isRegularFile(_)).foreach(println) 

您还要求提供文件匹配。 尝试java.nio.file.Files.findjava.nio.file.Files.newDirectoryStream

请参阅这里的文档: http : //docs.oracle.com/javase/tutorial/essential/io/walk.html

Apache Commons Io的FileUtils适合于一行,而且非常易读:

 import scala.collection.JavaConversions._ // important for 'foreach' import org.apache.commons.io.FileUtils FileUtils.listFiles(new File("c:\temp"), Array("foo"), true).foreach{ f => } 

看看scala.tools.nsc.io

有一些非常有用的实用工具,包括Directory类的深层列表function。

如果我没有记错的话,这可以通过反义词突出显示(可能是贡献),并且在io在标准库中得到一个新的更完整的实现之前,被视为一个权宜之计。

这里是来自@DuncanMcGregor的stream解决scheme与来自@ Rick-777的filter的混合:

  def tree( root: File, descendCheck: File => Boolean = { _ => true } ): Stream[File] = { require(root != null) def directoryEntries(f: File) = for { direntries <- Option(f.list).toStream d <- direntries } yield new File(f, d) val shouldDescend = root.isDirectory && descendCheck(root) ( root.exists, shouldDescend ) match { case ( false, _) => Stream.Empty case ( true, true ) => root #:: ( directoryEntries(root) flatMap { tree( _, descendCheck ) } ) case ( true, false) => Stream( root ) } } def treeIgnoringHiddenFilesAndDirectories( root: File ) = tree( root, { !_.isHidden } ) filter { !_.isHidden } 

这给你一个stream[文件],而不是(可能是巨大的和非常慢的)列表[文件],同时让你决定使用descendCheck()函数recursion到哪种types的目录。

怎么样

  def allFiles(path:File):List[File]= { val parts=path.listFiles.toList.partition(_.isDirectory) parts._2 ::: parts._1.flatMap(allFiles) } 

我个人喜欢@Rex Kerr提出的解决scheme的优雅和简单。 但是这里是一个尾recursion版本可能是什么样的:

 def listFiles(file: File): List[File] = { @tailrec def listFiles(files: List[File], result: List[File]): List[File] = files match { case Nil => result case head :: tail if head.isDirectory => listFiles(Option(head.listFiles).map(_.toList ::: tail).getOrElse(tail), result) case head :: tail if head.isFile => listFiles(tail, head :: result) } listFiles(List(file), Nil) } 

还没有人提到https://github.com/pathikrit/better-files

 val dir = "src"/"test" val matches: Iterator[File] = dir.glob("**/*.{java,scala}") // above code is equivalent to: dir.listRecursively.filter(f => f.extension == Some(".java") || f.extension == Some(".scala")) 

斯卡拉有图书馆“scala.reflect.io”考虑实验,但做的工作

 import scala.reflect.io.Path Path(path) walkFilter { p => p.isDirectory || """a*.foo""".r.findFirstIn(p.name).isDefined } 

这里有一个与Rex Kerr类似的解决scheme,但是包含一个文件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)) } 

该方法返回一个List [File],比Array [File]稍微方便一些。 它也会忽略所有隐藏的目录(即以'。'开始)。

部分应用您select的文件filter,例如:

 val srcDir = new File( ... ) val htmlFiles = findFiles( _.getName endsWith ".html" )( srcDir ) 

最简单的Scala解决scheme(如果您不介意需要Scala编译器库):

 val path = scala.reflect.io.Path(dir) scala.tools.nsc.io.Path.onlyFiles(path.walk).foreach(println) 

否则,@ Renaud的解决scheme是短而甜的(如果你不介意在Apache Commons FileUtils中):

 import scala.collection.JavaConversions._ // enables foreach import org.apache.commons.io.FileUtils FileUtils.listFiles(dir, null, true).foreach(println) 

dir是一个java.io.File:

 new File("path/to/dir") 

似乎没有人提到scala-incubator的scala-io

 import scalax.file.Path Path.fromString("c:\temp") ** "a*.foo" 

implicit

 import scalax.file.ImplicitConversions.string2path "c:\temp" ** "a*.foo" 

或者,如果你想明确implicit

 import scalax.file.Path import scalax.file.ImplicitConversions.string2path val dir: Path = "c:\temp" dir ** "a*.foo" 

文档可以在这里find: http : //jesseeichar.github.io/scala-io-doc/0.4.3/index.html#!/file/glob_based_pa​​th_sets

这个咒语适合我:

  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]())(_ ++ _) } } 

你可以使用尾recursion:

 object DirectoryTraversal { import java.io._ def main(args: Array[String]) { val dir = new File("C:/Windows") val files = scan(dir) val out = new PrintWriter(new File("out.txt")) files foreach { file => out.println(file) } out.flush() out.close() } def scan(file: File): List[File] = { @scala.annotation.tailrec def sc(acc: List[File], files: List[File]): List[File] = { files match { case Nil => acc case x :: xs => { x.isDirectory match { case false => sc(x :: acc, xs) case true => sc(acc, xs ::: x.listFiles.toList) } } } } sc(List(), List(file)) } } 

你为什么使用Java的文件而不是Scala的AbstractFile?

使用Scala的AbstractFile,迭代器支持允许编写更简洁的James Moore解决scheme:

 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) }