Scala:基于文件列表处理文件夹中文件的最有效方法

Scala: Most efficient way to process files in folder based on a file list

我正在尝试根据允许的文件列表找到处理多个文件夹中文件的最有效方法。

我有一个我应该处理的允许文件列表。

过程如下

  1. val allowedFiles = List("File1.json","File2.json","File3.json")
  2. 获取目录中的文件夹列表。为此,我可以使用:
      def getListOfSubDirectories(dir: File): List[String] =
            dir.listFiles
               .filter(_.isDirectory)
               .map(_.getName)
               .toList
  1. 遍历第 2 步中的每个文件夹并获取所有文件。为此,我会使用:
    def getListOfFiles(dir: String):List[File] = {
        val d = new File(dir)
        if (d.exists && d.isDirectory) {
            d.listFiles.filter(_.isFile).toList
        } else {
            List[File]()
        }
    }
  1. 如果第 3 步中的文件在允许的文件列表中,则调用另一个处理文件的方法

所以我需要遍历第一个目录,获取文件,检查文件是否需要处理,然后调用另一个函数。我在考虑双循环,它可以工作但是是最有效的方法。我知道在 scala 中我应该使用递归函数,但是调用额外方法的这个双递归函数失败了。

欢迎提出任何想法。

您可以使用Files.walk
代码看起来像这样(我没有编译它,所以它可能有一些错别字)

import java.nio.file.{Files, Path}
import scala.jdk.StreamConverters._

def getFilesRecursive(initialFolder: Path, allowedFiles: Set[String]): List[Path] =
  Files
    .walk(initialFolder)
    .filter(path => allowedFiles.contains(path.getFileName.toString.toLowerCase))
    .toScala(List)

Files.find() 将进行深度搜索和过滤。

import java.nio.file.{Files,Paths,Path}
import scala.jdk.StreamConverters._

def getListOfFiles(dir: String, targets:Set[String]): List[Path] =
  Files.find( Paths.get(dir)
            , 999
            , (p, _) => targets(p.getFileName.toString)
            ).toScala(List)

用法:

val lof = getListOfFiles("/DataDir",  allowedFiles.toSet)

但是,根据所需的处理类型,您可能不会返回 List,而是只处理遇到的每个文件。

import java.nio.file.{Files,Paths,Path}

def processFile(path: Path): Unit = ???
  
def processSelected(dir: String, targets:Set[String]): Unit =
  Files.find( Paths.get(dir)
            , 999
            , (p, _) => targets(p.getFileName.toString)
            ).forEach(processFile)

我不是 Scala 方面的专家(我上次涉足它可能是 18 年前)但我认为必须有一种方法来获取这段代码:

def getListOfSubDirectories(dir: File): List[String] =
    dir.listFiles
       .filter(_.isDirectory)
       .map(_.getName)
       .toList

并消除至少一个额外的列表创建。我发现 很有启发性,然后 Google 搜索 withFilter.

看起来你可以把上面的那一点翻译成下面的。通过将 filter 替换为 withFilter,不会创建新列表然后迭代。

def getListOfSubDirectories(dir: File): List[String] =
    dir.listFiles
       .withFilter(_.isDirectory)
       .map(_.getName)
       .toList