scala流以递归方式处理文件和子目录

时间:2016-03-29 23:35:59

标签: scala

我想为目录和子目录中的每个文件应用一个函数,如下所示:

  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)

1 个答案:

答案 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