Listar arquivos em um diretório
Você pode listar facilmente os nomes de todos os arquivos em um diretório usando o método list() da classe File. Se quiser obter outros arquivos além de nomes de arquivos, você pode usar o método listFiles(). Isso é muito simples, o difícil é como processar a lista retornada. Em vez de usar iteradores externos longos e tradicionais, usamos expressões funcionais elegantes para realmente percorrer esta lista. Aqui também temos que usar a nova interface CloseableStream do JDK e algumas funções de alta ordem relacionadas.
O código a seguir lista os nomes de todos os arquivos no diretório atual.
Copie o código do código da seguinte forma:
Arquivos.list(Paths.get("."))
.forEach(System.out::println);
Se quiser listar outros diretórios, você pode substituir "." pelo caminho completo do diretório que deseja acessar.
Aqui, primeiro usamos o método get() de Paths para criar uma instância de Path por meio de uma string. Em seguida, obtemos um objeto ClosableStream por meio do método list() da classe de ferramenta Arquivos e podemos usá-lo para percorrer todos os arquivos do diretório. Em seguida, usamos o iterador interno forEach() para imprimir o nome do arquivo. Vejamos primeiro alguns dos resultados de saída deste código: liste os arquivos e subdiretórios no diretório atual.
Copie o código do código da seguinte forma:
./aSampleFiles.txt
./bin
./fpij
...
Se quisermos obter apenas os subdiretórios do diretório atual, não os arquivos, podemos usar o método filter():
Copie o código do código da seguinte forma:
Arquivos.list(Paths.get("."))
.filter(Arquivos::isDiretório)
.forEach(System.out::println);
O método ilter() filtra diretórios do fluxo de arquivos. Passamos uma referência ao método isDirectory da classe Files em vez de passar uma expressão lambda. Lembre-se de que o método filter() requer um tipo Predicate que retorne um valor booleano, e esse método é o ideal. Finalmente usamos um iterador interno para imprimir o nome do diretório. O programa imprimirá os subdiretórios do diretório atual.
Copie o código do código da seguinte forma:
./bin
./fpij
./saída
...
É muito mais simples escrever dessa forma e economiza muito código em comparação com a antiga forma de escrever em Java. Vamos dar uma olhada em como listar arquivos que correspondem a um determinado padrão.
Listar arquivos especificados em um diretório
Java há muito fornece uma variante do método list() para filtrar nomes de arquivos. Esta versão do método list() aceita um parâmetro do tipo FilenameFilter. Esta interface possui apenas um método accept(), que aceita dois parâmetros: File dir (representando o diretório) e String name (representando o nome do arquivo). Se o método accept() retornar verdadeiro, o nome do arquivo aparecerá na lista retornada, caso contrário, não. Vamos implementar este método.
A abordagem habitual é passar uma instância de uma classe interna anônima que implementa a interface FilenameFilter para o método list(). Por exemplo, vamos dar uma olhada em como usar esse método para retornar o arquivo .java no diretório fpij.
Copie o código do código da seguinte forma:
String final[] arquivos =
novo arquivo("fpij").list(new java.io.FilenameFilter() {
public boolean aceitar(diretório do arquivo final, nome da string final) {
retornar nome.endsWith(".java");
}
});
System.out.println(arquivos);
Isso realmente leva algum tempo e esforço para escrever algumas linhas de código. Esse tipo de código é muito barulhento: criação de objetos, chamada de funções, definição de classes internas anônimas, incorporação de métodos em classes, etc. Não precisamos mais suportar essa dor, basta passar uma expressão lambda que aceita dois parâmetros e retorna um bolleano. O compilador Java cuidará do resto.
O exemplo anterior poderia simplesmente substituir os internos anônimos por uma expressão lambda, mas há espaço para otimização adicional. A nova ferramenta DirectoryStream pode nos ajudar a percorrer grandes estruturas de diretórios com mais eficiência. Vamos tentar este método. Esta é uma variante do método newDirectoryStream() que aceita um filtro adicional.
Copie o código do código da seguinte forma:
Arquivos.newDirectoryStream(
Paths.get("fpij"), caminho -> path.toString().endsWith(".java"))
.forEach(System.out::println);
Dessa forma, nos livramos da classe interna anônima e tornamos o código complicado conciso e claro. A saída de ambas as versões é a mesma. Vamos imprimir o arquivo especificado.
Este código produzirá apenas arquivos .java no diretório especificado. Aqui está parte de sua saída:
Copie o código do código da seguinte forma:
fpij/Compare.java
fpij/IterateString.java
fpij/ListDirs.java
...
Filtramos arquivos com base em nomes de arquivos. Ele também pode ser facilmente filtrado por atributos de arquivo, como se o arquivo é executável, legível, gravável, etc. Para fazer isso, você precisa de um método listFiles(), que aceita um parâmetro do tipo FileFilter. Ainda usamos expressões lambda em vez de criar classes internas anônimas. Agora vamos ver um exemplo de listagem de todos os arquivos ocultos no diretório atual.
Copie o código do código da seguinte forma:
final Arquivo[] arquivos = new Arquivo(".").listFiles(arquivo -> arquivo.isHidden());
Se estivermos operando um diretório grande, podemos usar DirectoryStream em vez de chamar o método File diretamente.
A assinatura da expressão lambda que passamos para o método listFiles() é igual à assinatura do método accept() da interface FileFilter. Esta expressão lambda aceita um parâmetro de uma instância de File. Neste exemplo, o nome do parâmetro é file. Se o arquivo tiver atributos ocultos, ele retornará verdadeiro, caso contrário, retornará falso.
Na verdade, o código pode ser ainda mais simplificado aqui. Não passamos expressões lambda. Passar uma referência de método fará com que o código pareça mais conciso:
Copie o código do código da seguinte forma:
new Arquivo(".").listFiles(Arquivo::isHidden);
Primeiro o implementamos usando expressões lambda e depois o refatoramos para ser mais conciso usando referências de método. Se escrevermos um novo código, é claro que devemos usar este método conciso. Se uma implementação tão elegante pudesse ser encontrada antecipadamente, certamente priorizaríamos seu uso. Existe um ditado chamado "faça funcionar primeiro, depois melhore". Depois de esclarecê-lo, consideraremos a simplicidade e o desempenho para otimização.
Usamos um exemplo para filtrar arquivos especificados de um diretório. Vamos dar uma olhada em como percorrer os subdiretórios em um diretório especificado.