Comment puis-je lister tous les fichiers d’un sous-répertoire dans scala?

Existe-t-il une bonne façon de lister récursivement les fichiers dans un répertoire? Qu’en est-il de la correspondance d’un modèle particulier?

Par exemple récursivement tous les fichiers correspondant à "a*.foo" dans c:\temp .

Le code Scala utilise généralement des classes Java pour gérer les E / S, y compris les répertoires de lecture. Donc, vous devez faire quelque chose comme:

 import java.io.File def recursiveListFiles(f: File): Array[File] = { val these = f.listFiles these ++ these.filter(_.isDirectory).flatMap(recursiveListFiles) } 

Vous pouvez collecter tous les fichiers puis filtrer en utilisant une regex:

 myBigFileArray.filter(f => """.*\.html$""".r.findFirstIn(f.getName).isDefined) 

Ou vous pouvez incorporer le regex dans la recherche récursive:

 import scala.util.matching.Regex def recursiveListFiles(f: File, r: Regex): Array[File] = { val these = f.listFiles val good = these.filter(f => r.findFirstIn(f.getName).isDefined) good ++ these.filter(_.isDirectory).flatMap(recursiveListFiles(_,r)) } 

Je préférerais une solution avec Streams parce que vous pouvez itérer sur un système de fichiers infini (les stream sont des collections évaluées paresseuses)

 import scala.collection.JavaConversions._ def getFileTree(f: File): Stream[File] = f #:: (if (f.isDirectory) f.listFiles().toStream.flatMap(getFileTree) else Stream.empty) 

Exemple de recherche

 getFileTree(new File("c:\\main_dir")).filter(_.getName.endsWith(".scala")).foreach(println) 
 for (file <- new File("c:\\").listFiles) { processFile(file) } 

http://langref.org/scala+java/files

À partir de Java 1.7, vous devriez tous utiliser java.nio. Il offre des performances proches de la normale (java.io est très lent) et dispose d’aides utiles

Mais Java 1.8 introduit exactement ce que vous recherchez:

 import java.nio.file.{FileSystems, Files} import scala.collection.JavaConverters._ val dir = FileSystems.getDefault.getPath("/some/path/here") Files.walk(dir).iterator().asScala.filter(Files.isRegularFile(_)).foreach(println) 

Vous avez également demandé une correspondance de fichier. Essayez java.nio.file.Files.find et aussi java.nio.file.Files.newDirectoryStream

Voir la documentation ici: http://docs.oracle.com/javase/tutorial/essential/io/walk.html

J’aime la solution de stream de yura, mais elle (et les autres) se retrouve dans des répertoires cachés. Nous pouvons également simplifier en utilisant le fait que listFiles renvoie null pour un non-répertoire.

 def tree(root: File, skipHidden: Boolean = false): Stream[File] = if (!root.exists || (skipHidden && root.isHidden)) Stream.empty else root #:: ( root.listFiles match { case null => Stream.empty case files => files.toStream.flatMap(tree(_, skipHidden)) }) 

Maintenant, nous pouvons lister les fichiers

 tree(new File(".")).filter(f => f.isFile && f.getName.endsWith(".html")).foreach(println) 

ou réaliser tout le stream pour un traitement ultérieur

 tree(new File("dir"), true).toArray 

Scala est un langage multi-paradigme. Une bonne façon d’itérer un répertoire serait de réutiliser un code existant!

J’envisagerais d’ utiliser commons-io comme une manière parfaitement itérative d’itérer un répertoire. Vous pouvez utiliser certaines conversions implicites pour le rendre plus facile. Comme

 import org.apache.commons.io.filefilter.IOFileFilter implicit def newIOFileFilter (filter: File=>Boolean) = new IOFileFilter { def accept (file: File) = filter (file) def accept (dir: File, name: Ssortingng) = filter (new java.io.File (dir, name)) } 

Le FileUtils d’ Apache Commons Io s’adapte sur une seule ligne et est très lisible:

 import scala.collection.JavaConversions._ // important for 'foreach' import org.apache.commons.io.FileUtils FileUtils.listFiles(new File("c:\temp"), Array("foo"), true).foreach{ f => } 

Personne n’a encore mentionné https://github.com/pathikrit/better-files

 val dir = "src"/"test" val matches: Iterator[File] = dir.glob("**/*.{java,scala}") // above code is equivalent to: dir.listRecursively.filter(f => f.extension == Some(".java") || f.extension == Some(".scala")) 

Jetez un oeil à scala.tools.nsc.io

Il existe des utilitaires très utiles, notamment des fonctionnalités de listage approfondi sur la classe Directory.

Si je me souviens bien, cela a été mis en évidence (éventuellement en consortingbuant) par retronym et ont été considérés comme un palliatif avant que io n’obtienne une nouvelle implémentation plus complète dans la bibliothèque standard.

Et voici un mélange de la solution de stream de @DuncanMcGregor avec le filtre de @ Rick-777:

  def tree( root: File, descendCheck: File => Boolean = { _ => true } ): Stream[File] = { require(root != null) def directoryEnsortinges(f: File) = for { dirensortinges <- Option(f.list).toStream d <- direntries } yield new File(f, d) val shouldDescend = root.isDirectory && descendCheck(root) ( root.exists, shouldDescend ) match { case ( false, _) => Stream.Empty case ( true, true ) => root #:: ( directoryEnsortinges(root) flatMap { tree( _, descendCheck ) } ) case ( true, false) => Stream( root ) } } def treeIgnoringHiddenFilesAndDirectories( root: File ) = tree( root, { !_.isHidden } ) filter { !_.isHidden } 

Cela vous donne un Stream [File] au lieu d’une List (File potentiellement énorme et très lent) tout en vous permettant de décider quels types de répertoires utiliser avec la fonction descendCheck ().

Que diriez-vous

  def allFiles(path:File):List[File]= { val parts=path.listFiles.toList.partition(_.isDirectory) parts._2 ::: parts._1.flatMap(allFiles) } 

Personnellement, j’aime l’élégance et la simplicité de la solution proposée par @Rex Kerr. Mais voici à quoi pourrait ressembler une version récursive de queue:

 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) } 

Scala a la bibliothèque ‘scala.reflect.io’ qui a considéré expérimental mais fait le travail

 import scala.reflect.io.Path Path(path) walkFilter { p => p.isDirectory || """a*.foo""".r.findFirstIn(p.name).isDefined } 

Voici une solution similaire à celle de Rex Kerr, mais intégrant un filtre de fichier:

 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)) } 

La méthode renvoie une liste [File], qui est légèrement plus pratique que Array [File]. Il ignore également tous les répertoires masqués (c’est-à-dire commençant par ‘.’).

Il est partiellement appliqué à l’aide d’un filtre de fichier de votre choix, par exemple:

 val srcDir = new File( ... ) val htmlFiles = findFiles( _.getName endsWith ".html" )( srcDir ) 

La solution la plus simple de Scala uniquement (si cela ne vous dérange pas d’exiger la bibliothèque de compilation Scala):

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

Sinon, la solution de @ Renaud est courte et douce (si cela ne vous dérange pas de tirer sur Apache Commons FileUtils):

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

dir est un java.io.File:

 new File("path/to/dir") 

Il semble que personne ne mentionne la bibliothèque scala-io de Scala-Incubrator …

 import scalax.file.Path Path.fromSsortingng("c:\temp") ** "a*.foo" 

Ou avec implicit

 import scalax.file.ImplicitConversions.ssortingng2path "c:\temp" ** "a*.foo" 

Ou si vous voulez implicit explicitement …

 import scalax.file.Path import scalax.file.ImplicitConversions.ssortingng2path val dir: Path = "c:\temp" dir ** "a*.foo" 

La documentation est disponible ici: http://jesseeichar.github.io/scala-io-doc/0.4.3/index.html#!/file/glob_based_path_sets

Cette incantation fonctionne pour moi:

  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]())(_ ++ _) } } 

Vous pouvez utiliser la récursion de la queue pour cela:

 object DirectoryTraversal { import java.io._ def main(args: Array[Ssortingng]) { 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)) } } 

Pourquoi utilisez-vous le fichier Java au lieu du fichier AbstractFile de Scala?

Avec AbstractFile de Scala, le support de l’iterator permet d’écrire une version plus concise de la solution de James Moore:

 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) }