Как мне перечислить все файлы в подкаталоге в Scala? - PullRequest
88 голосов
/ 14 апреля 2010

Есть ли хороший "scala-esque" (я думаю, я имею в виду функциональный) способ рекурсивного вывода файлов в каталоге? А как насчет соответствия определенного шаблона?

Например, рекурсивно все файлы, соответствующие "a*.foo" в c:\temp.

Ответы [ 19 ]

3 голосов
/ 14 апреля 2010

Взгляните на scala.tools.nsc.io

Там есть несколько очень полезных утилит, включая функцию глубокого перечисления в классе Directory.

Если я правильно помню, это было выделено (возможно, внесено) ретронимом и воспринималось как пробел, прежде чем io получит новую и более полную реализацию в стандартной библиотеке.

3 голосов
/ 25 апреля 2014

Мне лично нравится элегантность и простота предложенного решения @Rex Kerr. Но вот как может выглядеть хвостовая рекурсивная версия:

def listFiles(file: File): List[File] = {
  @tailrec
  def listFiles(files: List[File], result: List[File]): List[File] = files match {
    case Nil => result
    case head :: tail if head.isDirectory =>
      listFiles(Option(head.listFiles).map(_.toList ::: tail).getOrElse(tail), result)
    case head :: tail if head.isFile =>
      listFiles(tail, head :: result)
  }
  listFiles(List(file), Nil)
}
3 голосов
/ 21 февраля 2014

Scala имеет библиотеку 'scala.reflect.io', которая считается экспериментальной, но выполняет работу

import scala.reflect.io.Path
Path(path) walkFilter { p => 
  p.isDirectory || """a*.foo""".r.findFirstIn(p.name).isDefined
}
1 голос
/ 29 мая 2012

Вот решение, аналогичное Rex Kerr, но с фильтром файлов:

import java.io.File
def findFiles(fileFilter: (File) => Boolean = (f) => true)(f: File): List[File] = {
  val ss = f.list()
  val list = if (ss == null) {
    Nil
  } else {
    ss.toList.sorted
  }
  val visible = list.filter(_.charAt(0) != '.')
  val these = visible.map(new File(f, _))
  these.filter(fileFilter) ++ these.filter(_.isDirectory).flatMap(findFiles(fileFilter))
}

Метод возвращает List [File], что несколько удобнее, чем Array [File]. Также игнорируются все скрытые каталоги (т. Е. Начинающиеся с '.').

Он частично применяется с использованием фильтра файлов по вашему выбору, например:

val srcDir = new File( ... )
val htmlFiles = findFiles( _.getName endsWith ".html" )( srcDir )
1 голос
/ 07 июля 2015

Кажется, никто не упоминает библиотеку scala-io из scala-инкубатора ...

import scalax.file.Path

Path.fromString("c:\temp") ** "a*.foo"

Или с implicit

import scalax.file.ImplicitConversions.string2path

"c:\temp" ** "a*.foo"

Или, если хотите, implicit явно ...

import scalax.file.Path
import scalax.file.ImplicitConversions.string2path

val dir: Path = "c:\temp"
dir ** "a*.foo"

Документация доступна здесь: http://jesseeichar.github.io/scala-io-doc/0.4.3/index.html#!/file/glob_based_path_sets

1 голос
/ 29 апреля 2015

Самое простое решение только для Scala (если вы не возражаете против использования библиотеки компилятора Scala):

val path = scala.reflect.io.Path(dir)
scala.tools.nsc.io.Path.onlyFiles(path.walk).foreach(println)

В противном случае решение @ Renaud будет коротким и приятным (если вы не против использовать Apache Commons FileUtils):

import scala.collection.JavaConversions._  // enables foreach
import org.apache.commons.io.FileUtils
FileUtils.listFiles(dir, null, true).foreach(println)

Где dir - это файл java.io.File:

new File("path/to/dir")
0 голосов
/ 10 мая 2016

Вы можете использовать для этого хвостовую рекурсию:

object DirectoryTraversal {
  import java.io._

  def main(args: Array[String]) {
    val dir = new File("C:/Windows")
    val files = scan(dir)

    val out = new PrintWriter(new File("out.txt"))

    files foreach { file =>
      out.println(file)
    }

    out.flush()
    out.close()
  }

  def scan(file: File): List[File] = {

    @scala.annotation.tailrec
    def sc(acc: List[File], files: List[File]): List[File] = {
      files match {
        case Nil => acc
        case x :: xs => {
          x.isDirectory match {
            case false => sc(x :: acc, xs)
            case true => sc(acc, xs ::: x.listFiles.toList)
          }
        }
      }
    }

    sc(List(), List(file))
  }
}
0 голосов
/ 18 февраля 2013

У меня работает это заклинание:

  def findFiles(dir: File, criterion: (File) => Boolean): Seq[File] = {
    if (dir.isFile) Seq()
    else {
      val (files, dirs) = dir.listFiles.partition(_.isFile)
      files.filter(criterion) ++ dirs.toSeq.map(findFiles(_, criterion)).foldLeft(Seq[File]())(_ ++ _)
    }
  }
0 голосов
/ 22 января 2014

Почему вы используете Java-файл вместо Scala AbstractFile?

В Scala AbstractFile поддержка итератора позволяет написать более краткую версию решения Джеймса Мура:

import scala.reflect.io.AbstractFile  
def tree(root: AbstractFile, descendCheck: AbstractFile => Boolean = {_=>true}): Stream[AbstractFile] =
  if (root == null || !root.exists) Stream.empty
  else
    (root.exists, root.isDirectory && descendCheck(root)) match {
      case (false, _) => Stream.empty
      case (true, true) => root #:: root.iterator.flatMap { tree(_, descendCheck) }.toStream
      case (true, false) => Stream(root)
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...