tutorial software renault fungicida examples constructora blanquerna scala

software - ¿Cómo enumero todos los archivos en un subdirectorio en scala?



scala tutorial (19)

¿Existe una buena forma "scala-esque" (supongo que me refiero a funcional) de enumerar recursivamente los archivos en un directorio? ¿Qué hay de coincidir con un patrón en particular?

Por ejemplo, recursivamente todos los archivos que coincidan con "a*.foo" en c:/temp .


¿Por qué estás usando el archivo de Java en lugar del AbstractFile de Scala?

Con AbstractFile de Scala, el soporte del iterador permite escribir una versión más concisa de la solución 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) }


A partir de Java 1.7, todos deberían usar java.nio. Ofrece un rendimiento casi nativo (java.io es muy lento) y tiene algunos ayudantes útiles

Pero Java 1.8 presenta exactamente lo que estás buscando:

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)

También solicitó la coincidencia de archivos. Pruebe java.nio.file.Files.find y también java.nio.file.Files.newDirectoryStream

Consulte la documentación aquí: http://docs.oracle.com/javase/tutorial/essential/io/walk.html


Aquí hay una solución similar a la de Rex Kerr, pero que incorpora un filtro de archivos:

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

El método devuelve una Lista [Archivo], que es ligeramente más conveniente que la Matriz [Archivo]. También ignora todos los directorios que están ocultos (es decir, que comienzan con ''.'').

Se aplica parcialmente utilizando un filtro de archivos de su elección, por ejemplo:

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


Eche un vistazo a scala.tools.nsc.io

Hay algunas utilidades muy útiles que incluyen la funcionalidad de listado profundo en la clase Directory.

Si no recuerdo mal, esto fue resaltado (posiblemente contribuido) por retronym y se consideró como una solución provisional antes de que io obtenga una implementación nueva y más completa en la biblioteca estándar.


El FileUtils Apache Commons Io encaja en una línea y es bastante legible:

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


El código Scala típicamente usa clases Java para manejar E / S, incluyendo la lectura de directorios. Entonces tienes que hacer algo como:

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

Puede recopilar todos los archivos y luego filtrar utilizando una expresión regular:

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

O podría incorporar la expresión regular en la búsqueda recursiva:

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


Este encantamiento funciona para mí:

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


La solución más simple de Scala (si no te importa solicitar la biblioteca del compilador de Scala):

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

De lo contrario, la solución de @ Renaud es corta y dulce (si no te importa tirar en Apache Commons FileUtils):

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

Donde dir es un archivo java.io.File:

new File("path/to/dir")


Me gusta la solución de flujo de yura, pero ésta (y las demás) recurre a directorios ocultos. También podemos simplificar haciendo uso del hecho de que listFiles devuelve null para un no-directorio.

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

Ahora podemos listar archivos

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

o darse cuenta de todo el flujo para su posterior procesamiento

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


Nadie ha mencionado aún 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"))


Parece que nadie menciona la biblioteca scala-io de scala-incubrator ...

import scalax.file.Path Path.fromString("c:/temp") ** "a*.foo"

O con implicit

import scalax.file.ImplicitConversions.string2path "c:/temp" ** "a*.foo"

O si quieres implicit explícitamente ...

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

La documentación está disponible aquí: http://jesseeichar.github.io/scala-io-doc/0.4.3/index.html#!/file/glob_based_path_sets


Personalmente me gusta la elegancia y la simplicidad de la solución propuesta de @Rex Kerr. Pero aquí está lo que podría ser una versión recursiva de cola:

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


Preferiría la solución con Streams porque puede iterar sobre un sistema de archivos infinito (las secuencias son colecciones evaluadas de forma diferida)

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

Ejemplo para buscar

getFileTree(new File("c://main_dir")).filter(_.getName.endsWith(".scala")).foreach(println)


Puede usar recursividad de cola para ello:

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


Qué tal si

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


Scala es un lenguaje multi-paradigma. Una buena forma de escalar un directorio sería reutilizar un código existente.

Consideraría usar commons-io, una forma perfectamente escalar de iterar un directorio. Puede usar algunas conversiones implícitas para hacerlo más fácil. Me gusta

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: String) = filter (new java.io.File (dir, name)) }


Scala tiene la biblioteca ''scala.reflect.io'' que considera experimental pero hace el trabajo

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


Y aquí hay una mezcla de la solución de flujo de @DuncanMcGregor con el filtro de @ Rick-777:

def tree( root: File, descendCheck: File => Boolean = { _ => true } ): Stream[File] = { require(root != null) def directoryEntries(f: File) = for { direntries <- 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 #:: ( directoryEntries(root) flatMap { tree( _, descendCheck ) } ) case ( true, false) => Stream( root ) } } def treeIgnoringHiddenFilesAndDirectories( root: File ) = tree( root, { !_.isHidden } ) filter { !_.isHidden }

Esto le da una lista de Stream [Archivo] en lugar de una (potencialmente enorme y muy lenta) Lista [Archivo] al mismo tiempo que le permite decidir qué tipo de directorios recurrir en con la función descenCheck ().