2016-03-29 9 views
0

ich eine Funktion für jede Datei in einem Verzeichnis und dessen Unter anwenden möchten, wie folgt:scala Stream rekursiv Dateien und Unterverzeichnisse verarbeiten

def applyRecursively(dir: String, fn: (File) => Any) { 
    def listAndProcess(dir: File) { 
     dir.listFiles match { 
     case null => out.println("exception: dir cannot be listed: " + dir.getPath); List[File]() 
     case files => files.toList.sortBy(_.getName).foreach(file => { 
      fn(file) 
      if (file.isDirectory) listAndProcess(file) 
     }) 
     } 
    } 
    listAndProcess(new File(dir)) 
    } 

    def exampleFn(file: File) { println(s"processing $file") } 

    applyRecursively(dir, exampleFn) 

das funktioniert. zuvor sie answered wie diesen Code mit scala Iteratees umzuformen. Die Frage ist, wie ich diesen Code mit Hilfe von Scala-Streams umgestalten könnte. etwas wie folgt aus:

val stream: Stream[File] = ... // ??? 
stream.foreach(exampleFn) 
+0

'gelten eine Funktion für jede Datei' - für jede Datei oder für jede Datei-oder-Unterverzeichnis? sollte 'fn (file)' auch über Unterverzeichnisse aufgerufen werden? –

Antwort

3

Hier gehen Sie:

def fileStream(dir: File): Stream[File] = 
    Option(dir.listFiles).map(_.toList.sortBy(_.getName).toStream).map { 
    files => files.append(files.filter(_.isDirectory).flatMap(fileStream)) 
    } getOrElse { 
    println("exception: dir cannot be listed: " + dir.getPath) 
    Stream.empty 
    } 

aktualisieren: Implementierung über kehrt beide Dateien und Verzeichnisse. Hier ist, wie Verzeichnisse ausschließen effizient:

def fileStreamNoDirs(dir: File): Stream[File] = 
    Option(dir.listFiles).map(_.toList.sortBy(_.getName).toStream.partition(_.isDirectory)) 
    .map { case (dirs, files) => 
     files.append(dirs.flatMap(fileStreamNoDirs)) 
    } getOrElse { 
    println("exception: dir cannot be listed: " + dir.getPath) 
    Stream.empty 
    } 

jedoch einfach fileStream("/some/path").filterNot(_.isDirectory) wird die gleiche Arbeit tun.

Update2: Diese Variante bewahrt die Traversierfolgeliste des ursprünglichen Beispiel:

def fileStream(dir: File): Stream[File] = 
    if (dir.isDirectory) 
    Option(dir.listFiles) 
     .map(_.toList.sortBy(_.getName).toStream.flatMap(file => file #:: fileStream(file))) 
     .getOrElse { 
     println("exception: dir cannot be listed: " + dir.getPath) 
     Stream.empty 
     } 
    else Stream.empty 
+0

werden Unterverzeichnisse nicht selbst in die Liste der Dateien aufgenommen? Zugegeben, der ursprüngliche Code des Themas stater ruft 'fn' auch über Verzeichnissen auf, aber der Text seiner Frage suggeriert, dass es nicht seine Absicht war ... –

+1

@ Arioch'Das ist ein guter Punkt. Aktualisiert. – Aivean

+0

ja, ich wollte Unterverzeichnisse in die Liste der Datei, wie in dem bereitgestellten Code enthalten. Entschuldigung für den Text der Frage. –

Verwandte Themen