Listar arquivos recursivamente em Java

Como faço para listar recursivamente todos os arquivos em um diretório em Java? O framework fornece alguma utilidade?

Eu vi muitas implementações hacky. Mas nenhum da estrutura ou nio

O Java 8 fornece um stream legal para processar todos os arquivos em uma tree.

Files.walk(Paths.get(path)) .filter(Files::isRegularFile) .forEach(System.out::println); 

Isso fornece um caminho natural para percorrer arquivos. Como é um stream, você pode fazer todas as operações de stream no resultado, como limite, agrupamento, mapeamento, saída antecipada, etc.

UPDATE : Eu poderia apontar que também existe o Files.find que usa um BiPredicate que poderia ser mais eficiente se você precisasse verificar os atributos do arquivo.

 Files.find(Paths.get(path), Integer.MAX_VALUE, (filePath, fileAttr) -> fileAttr.isRegularFile()) .forEach(System.out::println); 

Observe que, embora o JavaDoc descubra que esse método poderia ser mais eficiente que o Files.walk, ele é efetivamente idêntico, a diferença de desempenho pode ser observada se você também estiver recuperando atributos de arquivo em seu filtro. No final, se você precisar filtrar os atributos, use Files.find , caso contrário, use Files.walk , principalmente porque há sobrecargas e é mais conveniente.

TESTES : Conforme solicitado, forneci uma comparação de desempenho de muitas das respostas. Confira o projeto do Github, que contém resultados e um caso de teste .

FileUtils tem methods listFiles e listFiles . Dê-lhes uma chance. (de commons-io )

Edit: Você pode verificar aqui para um benchmark de diferentes abordagens. Parece que a abordagem commons-io é lenta, então escolha alguns dos mais rápidos daqui (se for importante)

// Pronto para correr

 import java.io.File; public class Filewalker { public void walk( String path ) { File root = new File( path ); File[] list = root.listFiles(); if (list == null) return; for ( File f : list ) { if ( f.isDirectory() ) { walk( f.getAbsolutePath() ); System.out.println( "Dir:" + f.getAbsoluteFile() ); } else { System.out.println( "File:" + f.getAbsoluteFile() ); } } } public static void main(String[] args) { Filewalker fw = new Filewalker(); fw.walk("c:\\" ); } } 

O Java 7 terá o Files.walkFileTree :

Se você fornecer um ponto de partida e um visitante de arquivo, ele invocará vários methods no visitante do arquivo enquanto percorre o arquivo na tree de arquivos. Esperamos que as pessoas usem isso se estiverem desenvolvendo uma cópia recursiva, uma movimentação recursiva, uma exclusão recursiva ou uma operação recursiva que defina permissions ou execute outra operação em cada um dos arquivos.

Agora há um tutorial inteiro do Oracle sobre essa questão .

Nenhuma biblioteca externa necessária.
Retorna uma coleção para que você possa fazer o que quiser com ela após a chamada.

 public static Collection listFileTree(File dir) { Set fileTree = new HashSet(); if(dir==null||dir.listFiles()==null){ return fileTree; } for (File entry : dir.listFiles()) { if (entry.isFile()) fileTree.add(entry); else fileTree.addAll(listFileTree(entry)); } return fileTree; } 

Eu iria com algo como:

 public void list(File file) { System.out.println(file.getName()); File[] children = file.listFiles(); for (File child : children) { list(child); } } 

O System.out.println está lá apenas para indicar para fazer algo com o arquivo. não há necessidade de diferenciar entre arquivos e diretórios, já que um arquivo normal simplesmente terá zero filhos.

apenas escreva você mesmo usando recursion simples:

 public List addFiles(List files, File dir) { if (files == null) files = new LinkedList(); if (!dir.isDirectory()) { files.add(dir); return files; } for (File file : dir.listFiles()) addFiles(files, file); return files; } 

Eu prefiro usar uma fila em recursion para esse tipo de travessia simples:

 List allFiles = new ArrayList(); Queue dirs = new LinkedList(); dirs.add(new File("/start/dir/")); while (!dirs.isEmpty()) { for (File f : dirs.poll().listFiles()) { if (f.isDirectory()) { dirs.add(f); } else if (f.isFile()) { allFiles.add(f); } } } 

Com o Java 7, você pode usar a seguinte class:

 import java.io.IOException; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; public class MyFileIterator extends SimpleFileVisitor { public MyFileIterator(String path) throws Exception { Files.walkFileTree(Paths.get(path), this); } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attributes) throws IOException { System.out.println("File: " + file); return FileVisitResult.CONTINUE; } @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attributes) throws IOException { System.out.println("Dir: " + dir); return FileVisitResult.CONTINUE; } } 

Eu acho que isso deveria fazer o trabalho:

 File dir = new File(dirname); String[] files = dir.list(); 

Desta forma você tem arquivos e dirs. Agora use recursion e faça o mesmo para dirs (a class File tem o método isDirectory() ).

No Java 8, agora podemos usar o utilitário Files para percorrer uma tree de arquivos. Muito simples.

 Files.walk(root.toPath()) .filter(path -> !Files.isDirectory(path)) .forEach(path -> System.out.println(path)); 

Além da travessia recursiva, também é possível usar uma abordagem baseada em visitantes.

Abaixo do código é usado a abordagem baseada em visitantes para o percurso. Espera-se que a input para o programa seja o diretório raiz a ser percorrido.

 public interface Visitor { void visit(DirElement d); void visit(FileElement f); } public abstract class Element { protected File rootPath; abstract void accept(Visitor v); @Override public String toString() { return rootPath.getAbsolutePath(); } } public class FileElement extends Element { FileElement(final String path) { rootPath = new File(path); } @Override void accept(final Visitor v) { v.visit(this); } } public class DirElement extends Element implements Iterable { private final List elemList; DirElement(final String path) { elemList = new ArrayList(); rootPath = new File(path); for (File f : rootPath.listFiles()) { if (f.isDirectory()) { elemList.add(new DirElement(f.getAbsolutePath())); } else if (f.isFile()) { elemList.add(new FileElement(f.getAbsolutePath())); } } } @Override void accept(final Visitor v) { v.visit(this); } public Iterator iterator() { return elemList.iterator(); } } public class ElementWalker { private final String rootDir; ElementWalker(final String dir) { rootDir = dir; } private void traverse() { Element d = new DirElement(rootDir); d.accept(new Walker()); } public static void main(final String[] args) { ElementWalker t = new ElementWalker("C:\\temp"); t.traverse(); } private class Walker implements Visitor { public void visit(final DirElement d) { System.out.println(d); for(Element e:d) { e.accept(this); } } public void visit(final FileElement f) { System.out.println(f); } } } 

Você pode usar o código abaixo para obter uma lista de arquivos de pasta ou diretório específicos recursivamente.

 public static void main(String args[]) { recusiveList("D:"); } public static void recursiveList(String path) { File f = new File(path); File[] fl = f.listFiles(); for (int i = 0; i < fl.length; i++) { if (fl[i].isDirectory() && !fl[i].isHidden()) { System.out.println(fl[i].getAbsolutePath()); recusiveList(fl[i].getAbsolutePath()); } else { System.out.println(fl[i].getName()); } } } 

Este código está pronto para ser executado

 public static void main(String... args) { File[] files = new File("C:/").listFiles(); if (files != null) getFile(files); } public static void getFile(File[] files) { for (File file : files) { if (file.isDirectory()) { getFile(file.listFiles()); } else { System.out.println("File: " + file.toString()); } } } 

BFS não recursivo com uma única lista (um exemplo específico está procurando por arquivos * .eml):

  final FileFilter filter = new FileFilter() { @Override public boolean accept(File file) { return file.isDirectory() || file.getName().endsWith(".eml"); } }; // BFS recursive search List queue = new LinkedList(); queue.addAll(Arrays.asList(dir.listFiles(filter))); for (ListIterator itr = queue.listIterator(); itr.hasNext();) { File file = itr.next(); if (file.isDirectory()) { itr.remove(); for (File f: file.listFiles(filter)) itr.add(f); } } 

Minha versão (claro que eu poderia ter usado o walk in Java 8 ;-)):

 public static List findFilesIn(File rootDir, Predicate predicate) { ArrayList collected = new ArrayList<>(); walk(rootDir, predicate, collected); return collected; } private static void walk(File dir, Predicate filterFunction, List collected) { Stream.of(listOnlyWhenDirectory(dir)) .forEach(file -> walk(file, filterFunction, addAndReturn(collected, file, filterFunction))); } private static File[] listOnlyWhenDirectory(File dir) { return dir.isDirectory() ? dir.listFiles() : new File[]{}; } private static List addAndReturn(List files, File toAdd, Predicate filterFunction) { if (filterFunction.test(toAdd)) { files.add(toAdd); } return files; } 

O exemplo gera arquivos * .csv na pesquisa recursiva de diretório Subdiretórios usando Files.find () de java.nio:

 String path = "C:/Daten/ibiss/ferret/"; logger.debug("Path:" + path); try (Stream fileList = Files.find(Paths.get(path), Integer.MAX_VALUE, (filePath, fileAttr) -> fileAttr.isRegularFile() && filePath.toString().endsWith("csv"))) { List someThingNew = fileList.sorted().map(String::valueOf).collect(Collectors.toList()); for (String t : someThingNew) { t.toString(); logger.debug("Filename:" + t); } } 

Postando este exemplo, como eu tive dificuldade em entender como passar o parâmetro filename no exemplo # 1 dado por Bryan, usando foreach em Stream-result –

Espero que isto ajude.

Aqui uma solução simples, mas perfeitamente funcional, usando recursion :

 public static List listFiles(String rootDirectory) { List files = new ArrayList<>(); listFiles(rootDirectory, files); return files; } private static void listFiles(String path, List collectedFiles) { File root = new File(path); File[] files = root.listFiles(); if (files == null) { return; } for (File file : files) { if (file.isDirectory()) { listFiles(file.getAbsolutePath(), collectedFiles); } else { collectedFiles.add(file.toPath()); } } } 
  private void fillFilesRecursively(File file, List resultFiles) { if (file.isFile()) { resultFiles.add(file); } else { for (File child : file.listFiles()) { fillFilesRecursively(child, resultFiles); } } } 

Baseado na resposta do stacker. Aqui está uma solução que funciona no JSP sem nenhuma biblioteca externa, portanto você pode colocá-la em praticamente qualquer lugar em seu servidor:

 < !DOCTYPE html> < %@ page session="false" %> < %@ page import="java.util.*" %> < %@ page import="java.io.*" %> < %@ page contentType="text/html; charset=UTF-8" %> < %! public List files = new ArrayList(); /** Fills files array with all sub-files. */ public void walk( File root ) { File[] list = root.listFiles(); if (list == null) return; for ( File f : list ) { if ( f.isDirectory() ) { walk( f ); } else { files.add(f.getAbsolutePath()); } } } %> < % files.clear(); File jsp = new File(request.getRealPath(request.getServletPath())); File dir = jsp.getParentFile(); walk(dir); String prefixPath = dir.getAbsolutePath() + "/"; %> 

Então você acabou de fazer algo como:

  
    < % for (String file : files) { %> < % if (file.matches(".+\\.(apk|ipa|mobileprovision)")) { %>
  • < %=file.replace(prefixPath, "")%>
  • < % } %> < % } %>