我想为目录和子目录中的每个文件应用一个函数,如下所示:
def applyRecursively(dir: String, fn: (File) => Any) {
def listAndProcess(dir: File) {
dir.listFiles match {
case null => out.println("exception: dir cannot be listed: " + dir.getPath); List[File]()
case files => files.toList.sortBy(_.getName).foreach(file => {
fn(file)
if (file.isDirectory) listAndProcess(file)
})
}
}
listAndProcess(new File(dir))
}
def exampleFn(file: File) { println(s"processing $file") }
applyRecursively(dir, exampleFn)
这是有效的。以前他们answered如何使用scala Iteratees重构此代码。这里的问题是如何使用scala Streams重构此代码。
像这样的东西:
val stream: Stream[File] = ... // ???
stream.foreach(exampleFn)
答案 0 :(得分:4)
你走了:
def fileStream(dir: File): Stream[File] =
Option(dir.listFiles).map(_.toList.sortBy(_.getName).toStream).map {
files => files.append(files.filter(_.isDirectory).flatMap(fileStream))
} getOrElse {
println("exception: dir cannot be listed: " + dir.getPath)
Stream.empty
}
更新:上面的实现会返回文件和目录。以下是有效排除目录的方法:
def fileStreamNoDirs(dir: File): Stream[File] =
Option(dir.listFiles).map(_.toList.sortBy(_.getName).toStream.partition(_.isDirectory))
.map { case (dirs, files) =>
files.append(dirs.flatMap(fileStreamNoDirs))
} getOrElse {
println("exception: dir cannot be listed: " + dir.getPath)
Stream.empty
}
但是,简单的fileStream("/some/path").filterNot(_.isDirectory)
将完成同样的工作。
Update2 :此变体保留原始示例的遍历顺序:
def fileStream(dir: File): Stream[File] =
if (dir.isDirectory)
Option(dir.listFiles)
.map(_.toList.sortBy(_.getName).toStream.flatMap(file => file #:: fileStream(file)))
.getOrElse {
println("exception: dir cannot be listed: " + dir.getPath)
Stream.empty
}
else Stream.empty