【问题标题】:Scala: Most efficient way to process files in folder based on a file listScala:基于文件列表处理文件夹中文件的最有效方法
【发布时间】:2021-11-17 21:17:57
【问题描述】:

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

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

流程如下

  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 中我应该使用递归函数,但是这个双递归函数调用额外方法失败了。

欢迎任何想法。

【问题讨论】:

    标签: scala loops recursion functional-programming nested-loops


    【解决方案1】:

    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)
    

    【讨论】:

      【解决方案2】:

      您可以使用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)
      

      【讨论】:

        【解决方案3】:

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

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

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

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

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

        【讨论】:

        • Streams 是懒惰的,因此它们只迭代一次并将所有转换/过滤器​​混合在一个循环中。
        • 18 年前?根据Wikipedia 的说法,它于 2004 年首次出现。您一定参与了预发布。 ;-)
        • 您应该会印象深刻,我没有查看它就关闭了 那个!我只知道那是很久以前的事了。
        • 感谢您的精彩提示,我今天将对其进行测试
        猜你喜欢
        • 2019-04-20
        • 2012-02-11
        • 1970-01-01
        • 2014-12-31
        • 1970-01-01
        • 2011-04-05
        • 2011-12-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多