2016-03-29 6 views
0

Я хочу, чтобы применить функцию для каждого файла в каталоге и подкаталогах, следующим образом:поток Scala рекурсивно обрабатывать файлы и подкаталоги

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) 

это работает. ранее они answered как отредактировать этот код с помощью scala Iteratees. Вопрос здесь в том, как я мог бы реорганизовать этот код с помощью потоков Scala. что-то вроде этого:

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

'применить функцию для каждого файла' - для каждого файла, или для каждого файла-или-подкаталог? должен ли 'fn (файл)' также вызываться над подкаталогами? –

ответ

3

Здесь вы идете:

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 
    } 

Update: Реализация выше возвращается к файлам и каталогам. Вот как эффективно исключить каталоги:

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 
    } 

Однако простой fileStream("/some/path").filterNot(_.isDirectory) будет делать ту же работу.

Update2: Этот вариант сохраняет порядок обхода исходного примера:

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

ли он не включит сами подкаталоги в список файлов? Конечно, исходный код темы stater вызывает 'fn' над каталогами тоже, но текст его вопроса предполагает, что это было не его намерение .... –

+1

@ Arioch'The, хороший момент. Обновлено. – Aivean

+0

Да, я хотел включить подкаталоги в список файлов, как в приведенном коде. извините за текст вопроса. –

Смежные вопросы