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

Posted

技术标签:

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

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

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

流程如下

    val allowedFiles = List("File1.json","File2.json","File3.json") 获取目录中的文件夹列表。为此,我可以使用:
      def getListOfSubDirectories(dir: File): List[String] =
            dir.listFiles
               .filter(_.isDirectory)
               .map(_.getName)
               .toList
    遍历步骤 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]()
        
    
    如果第 3 步中的文件在允许的文件列表中,则调用另一个处理该文件的方法

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

欢迎任何想法。

【问题讨论】:

【参考方案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 年首次出现。您一定参与了预发布。 ;-) 您应该会印象深刻,我没有查看它就关闭了 那个!我只知道那是很久以前的事了。 感谢您的精彩提示,我今天将对其进行测试

以上是关于Scala:基于文件列表处理文件夹中文件的最有效方法的主要内容,如果未能解决你的问题,请参考以下文章

将标头记录(或字符串/文件)添加到 Scala / Java 中的大文件中

在巨大列表中查找/搜索的最有效方法(python)

如何在 Scala 中处理大列表?

基于嵌套列表中包含的 id 元素比较两个通用列表的最有效方法 (C#)

将 Access 2003 列表框行源(查询)导出到 Excel 2003 的最有效方法

处理大量承诺的最有效方式?