是否有一个好的"scala-esque"(我想我的意思是功能性)递归列出目录中的文件的方式?匹配特定模式怎么样?
例如递归的所有文件匹配"a*.foo"在c:\temp.
Rex*_*err 109
Scala代码通常使用Java类来处理I/O,包括读取目录.所以你必须做以下事情:
import java.io.File
def recursiveListFiles(f: File): Array[File] = {
val these = f.listFiles
these ++ these.filter(_.isDirectory).flatMap(recursiveListFiles)
}
Run Code Online (Sandbox Code Playgroud)
您可以收集所有文件,然后使用正则表达式进行过滤:
myBigFileArray.filter(f => """.*\.html$""".r.findFirstIn(f.getName).isDefined)
Run Code Online (Sandbox Code Playgroud)
或者您可以将正则表达式合并到递归搜索中:
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))
}
Run Code Online (Sandbox Code Playgroud)
yur*_*ura 45
我更喜欢Streams的解决方案,因为你可以迭代无限的文件系统(Streams是懒惰的评估集合)
import scala.collection.JavaConversions._
def getFileTree(f: File): Stream[File] =
f #:: (if (f.isDirectory) f.listFiles().toStream.flatMap(getFileTree)
else Stream.empty)
Run Code Online (Sandbox Code Playgroud)
搜索示例
getFileTree(new File("c:\\main_dir")).filter(_.getName.endsWith(".scala")).foreach(println)
Run Code Online (Sandbox Code Playgroud)
Phi*_*hil 20
for (file <- new File("c:\\").listFiles) { processFile(file) }
Run Code Online (Sandbox Code Playgroud)
http://langref.org/scala+java/files
mon*_*onj 20
从Java 1.7开始,你们都应该使用java.nio.它提供接近本机的性能(java.io非常慢)并且有一些有用的帮助器
但Java 1.8正是您正在寻找的内容:
import java.nio.file.{FileSystems, Files}
import scala.collection.JavaConverters._
val dir = FileSystems.getDefault.getPath("/some/path/here")
Files.walk(dir).iterator().asScala.filter(Files.isRegularFile(_)).foreach(println)
Run Code Online (Sandbox Code Playgroud)
您还要求文件匹配.尝试java.nio.file.Files.find也java.nio.file.Files.newDirectoryStream
请参阅此处的文档:http://docs.oracle.com/javase/tutorial/essential/io/walk.html
Art*_*mGr 11
Scala是一种多范式语言.迭代目录的一种好的"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))
}
Run Code Online (Sandbox Code Playgroud)
Dun*_*gor 11
我喜欢yura的流解决方案,但它(和其他人)会进入隐藏目录.我们还可以通过利用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))
})
Run Code Online (Sandbox Code Playgroud)
现在我们可以列出文件
tree(new File(".")).filter(f => f.isFile && f.getName.endsWith(".html")).foreach(println)
Run Code Online (Sandbox Code Playgroud)
或者实现整个流以供以后处理
tree(new File("dir"), true).toArray
Run Code Online (Sandbox Code Playgroud)
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 =>
}
Run Code Online (Sandbox Code Playgroud)
小智 5
我个人喜欢 @Rex Kerr 提出的解决方案的优雅和简单。但尾递归版本可能如下所示:
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)
}
Run Code Online (Sandbox Code Playgroud)
没人提到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"))
Run Code Online (Sandbox Code Playgroud)