Acabei de concluir os Resultados do teste que fornecem testes de desempenho para muitas das respostas. Não é de surpreender que todas as respostas baseadas em NIO tenham melhor desempenho. A resposta do commons-io é claramente o pior desempenho, com mais do dobro da duração da execução.
Brett Ryan
2
Java8: Files.walk?
214 Benj
Respostas:
327
O Java 8 fornece um bom fluxo para processar todos os arquivos em uma árvore.
Isso fornece uma maneira natural de percorrer arquivos. Como é um fluxo, você pode realizar todas as operações de fluxo agradáveis no resultado, como limite, agrupamento, mapeamento, saída antecipada etc.
UPDATE : Eu posso apontar que também existe o Files.find, que utiliza um BiPredicate que pode ser mais eficiente se você precisar verificar os atributos do arquivo.
Observe que, embora o JavaDoc ilude que esse método possa 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.
Um desses exemplos que podem mostrar a mágica da programação funcional, mesmo para iniciantes.
Johnny
2
Como o desempenho disso se compara aos métodos pré-java 8? Minha passagem de diretório atual é muito lenta e estou procurando por algo que o acelere.
Sridhar Sarnobat
1
Estou escrevendo alguns testes que contêm a maioria das variantes nas respostas fornecidas. Até agora, parece que usar Files.walkcom um fluxo paralelo é o melhor, seguido de perto pelo Files.walkFileTreequal é apenas um pouco mais lento. A resposta aceita usando commons-io é de longe a mais lenta em meus testes, sendo 4 vezes mais lenta.
Brett Ryan
1
@BrettRyan, tentei sua solução, mas recebo uma exceção Exception in thread "main" java.io.UncheckedIOException: java.nio.file.AccessDeniedException. Como eu poderia corrigi-lo
Edit: Você pode conferir aqui uma referência de diferentes abordagens. Parece que a abordagem commons-io é lenta, então escolha algumas das mais rápidas daqui (se for o caso)
FYI / TLDR: se você quiser listar todos os arquivos recursivamente sem filtragem, faça FileUtils.listFiles(dir, TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE), onde diré um objeto File que aponta para o diretório base.
precisa saber é o seguinte
2
Você pode considerar o uso listFilesAndDirs(), pois listFiles()não retorna pastas vazias.
Schnatterer
1
@ MikeFHay Olhando para o código do FileUtils, acho que seria FileUtils.listFiles(dir, true, true). using FileUtils.listFiles(dir, null, true)lançará uma exceção, enquanto FileUtils.listFiles(dir, true, null)listará todos os arquivos sem procurar em subdiretórios.
Ocramot 23/05
Que tal uma biblioteca nativa JDK? Eu posso implementar isso com facilidade, mas eu seria simplesmente C&P de outros lugares
Christian Bongiorno
1
Estou colocando alguns testes juntos, mas até agora isso parece ter um desempenho quatro vezes mais lento do que o uso de alternativas JDK8 ou JDK7. Os links simbólicos também provam ser problemáticos com essa abordagem, especialmente quando eles são vinculados a diretórios mais altos na árvore, isso faz com que o método nunca retorne, isso pode ser evitado ao manipular o filtro, mas, infelizmente, os links simbólicos em si não são visitados, mesmo que um arquivo.
Brett Ryan
138
// Pronto para correr
import java.io.File;publicclassFilewalker{publicvoid walk(String path ){File root =newFile( 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());}}}publicstaticvoid main(String[] args){Filewalker fw =newFilewalker();
fw.walk("c:\\");}}
Lembre-se de que para links simbólicos que apontam para um caminho mais alto na hierarquia de caminhos fará com que o método nunca termine. Considere um caminho com um link simbólico que aponte para -> ..
Brett Ryan #
2
Essa é apenas uma implementação ruim do Files.walkFileTree. Eu recomendaria que as pessoas olhassem para FIles.walkFileTree em vez de tentar lançá-lo você mesmo ... Ele está lidando com o problema exato que @BrettRyan apontou.
Tyler Nichols
Obrigado por incluir o arquivo import java.io.File ;. Muitos exemplos esquecem-se de incluir o material do namespace ou mesmo o tipo de dados, tornando o exemplo um ponto de partida em uma viagem de descoberta. Aqui este exemplo está pronto para ser executado. Obrigado.
22419 barrypicker
O caminho pode variar dependendo de onde está o arquivo Filewalker. Use "/", "./"ou "../"para diretório raiz, diretório de trabalho atual e diretório pai, respectivamente
Se você fornecer um ponto de partida e um visitante do arquivo, ele invocará vários métodos no visitante do arquivo enquanto ele percorre o arquivo na árvore 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 permissões ou execute outra operação em cada um dos arquivos.
publicvoid 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 arquivos e diretórios, pois um arquivo normal terá simplesmente zero filhos.
Por favor! deixe o chamador inicializar a lista de arquivos para que não precise verificar sua nulidade a cada vez. Se você deseja criar um segundo método (público) que cria a lista, chama esse método interno e retorna a lista completa.
helios
1
tanto faz. um cheque nulo não é muito caro, conveniência + preferência pessoal, de lado, acho que ele entenderá.
pstanton
Você pode explicar um pouco mais detalhadamente?
uday 30/01
8
Eu acho que isso deve fazer o trabalho:
File dir =newFile(dirname);String[] files = dir.list();
Dessa forma, você tem arquivos e diretórios. Agora use recursão e faça o mesmo para dirs (a Fileclasse possui o isDirectory()método).
A resposta aceita é ótima, porém é interrompida quando você deseja fazer IO dentro do lambda.
Aqui está o que você pode fazer se sua ação declarar IOExceptions.
Você pode tratar o fluxo filtrado como um Iterablee executar sua ação regularmente para cada loop. Dessa forma, você não precisa lidar com exceções dentro de uma lambda.
try(Stream<Path> pathStream =Files.walk(Paths.get(path)).filter(Files::isRegularFile)){for(Path file :(Iterable<Path>) pathStream::iterator){// something that throws IOExceptionFiles.copy(file,System.out);}}
Postando este exemplo, como tive problemas para entender como passar o parâmetro filename no exemplo # 1 dado por Bryan, usando foreach em Stream-result -
Produzirá uma lista de texto de todos os arquivos não pertencentes ao diretório em uma determinada raiz, um arquivo por linha com o caminho relativo à raiz e ao comprimento.
Com base na resposta do empilhador. Aqui está uma solução trabalhando em JSP sem bibliotecas externas, para que você possa colocá-lo em praticamente qualquer lugar do seu servidor:
<!DOCTYPE html><%@ page session="false"%><%@ page import="java.util.*"%><%@ page import="java.io.*"%><%@ page contentType="text/html; charset=UTF-8"%><%!publicList<String> files =newArrayList<String>();/**
Fills files array with all sub-files.
*/publicvoid 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 =newFile(request.getRealPath(request.getServletPath()));File dir = jsp.getParentFile();
walk(dir);String prefixPath = dir.getAbsolutePath()+"/";%>
Embora provavelmente funcione, a pergunta é sobre navegação de arquivos, não renderização de arquivos navegados. Exponha melhor seu algoritmo como tal, não é uma prática recomendada incorporar lógica de negócios em um JSP.
Samuel Kerrien 15/06/2015
Isso depende do que você está fazendo. Em um aplicativo de tamanho empresarial, você está absolutamente certo. Se você só precisa disso como um drop-in para uma lista simples e autônoma, tudo está perfeitamente bem.
Respostas:
O Java 8 fornece um bom fluxo para processar todos os arquivos em uma árvore.
Isso fornece uma maneira natural de percorrer arquivos. Como é um fluxo, você pode realizar todas as operações de fluxo agradáveis no resultado, como limite, agrupamento, mapeamento, saída antecipada etc.
UPDATE : Eu posso apontar que também existe o Files.find, que utiliza um BiPredicate que pode ser mais eficiente se você precisar verificar os atributos do arquivo.
Observe que, embora o JavaDoc ilude que esse método possa 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, forneço uma comparação de desempenho de muitas das respostas. Confira o projeto Github, que contém resultados e um caso de teste .
fonte
Files.walk
com um fluxo paralelo é o melhor, seguido de perto peloFiles.walkFileTree
qual é apenas um pouco mais lento. A resposta aceita usando commons-io é de longe a mais lenta em meus testes, sendo 4 vezes mais lenta.Exception in thread "main" java.io.UncheckedIOException: java.nio.file.AccessDeniedException
. Como eu poderia corrigi-loOs FileUtils têm
iterateFiles
elistFiles
métodos. Faça uma tentativa. (de commons-io )Edit: Você pode conferir aqui uma referência de diferentes abordagens. Parece que a abordagem commons-io é lenta, então escolha algumas das mais rápidas daqui (se for o caso)
fonte
FileUtils.listFiles(dir, TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE)
, ondedir
é um objeto File que aponta para o diretório base.listFilesAndDirs()
, poislistFiles()
não retorna pastas vazias.FileUtils.listFiles(dir, true, true)
. usingFileUtils.listFiles(dir, null, true)
lançará uma exceção, enquantoFileUtils.listFiles(dir, true, null)
listará todos os arquivos sem procurar em subdiretórios.// Pronto para correr
fonte
-> .
."/"
,"./"
ou"../"
para diretório raiz, diretório de trabalho atual e diretório pai, respectivamenteJava 7
terátem Files.walkFileTree :Agora existe um tutorial completo do Oracle sobre esta questão .
fonte
Nenhuma biblioteca externa é necessária.
Retorna uma coleção para que você possa fazer o que quiser com ela após a chamada.
fonte
Eu iria com algo como:
O System.out.println está lá apenas para indicar para fazer algo com o arquivo. não há necessidade de diferenciar arquivos e diretórios, pois um arquivo normal terá simplesmente zero filhos.
fonte
listFiles()
: “Se esse nome de caminho abstrato não indicar um diretório, esse método retornaránull
.”Prefiro usar uma fila em vez de recursão para esse tipo de deslocamento simples:
fonte
basta escrever você mesmo usando recursão simples:
fonte
Eu acho que isso deve fazer o trabalho:
Dessa forma, você tem arquivos e diretórios. Agora use recursão e faça o mesmo para dirs (a
File
classe possui oisDirectory()
método).fonte
Com o Java 7, você pode usar a seguinte classe:
fonte
No Java 8, agora podemos usar o utilitário Arquivos para percorrer uma árvore de arquivos. Muito simples.
fonte
Este código está pronto para ser executado
fonte
Além da travessia recursiva, também é possível usar uma abordagem baseada no visitante.
O código abaixo usa a abordagem baseada no visitante para a travessia. Espera-se que a entrada do programa seja o diretório raiz a ser percorrido.
fonte
Você pode usar o código abaixo para obter recursivamente uma lista de arquivos de pastas ou diretórios específicos.
fonte
A resposta aceita é ótima, porém é interrompida quando você deseja fazer IO dentro do lambda.
Aqui está o que você pode fazer se sua ação declarar IOExceptions.
Você pode tratar o fluxo filtrado como um
Iterable
e executar sua ação regularmente para cada loop. Dessa forma, você não precisa lidar com exceções dentro de uma lambda.Encontrei esse truque aqui: https://stackoverflow.com/a/32668807/1207791
fonte
BFS não recursivo com uma única lista (exemplo particular está pesquisando arquivos * .eml):
fonte
Minha versão (é claro que eu poderia ter usado a caminhada incorporada no Java 8 ;-)):
fonte
Aqui está uma solução simples, mas perfeitamente funcional, usando
recursion
:fonte
fonte
Eu vim com isso para imprimir todos os arquivos / nomes de arquivos recursivamente.
fonte
Exemplo gera arquivos * .csv em subdiretórios de pesquisa recursiva de diretório usando Files.find () de java.nio:
Postando este exemplo, como tive problemas para entender como passar o parâmetro filename no exemplo # 1 dado por Bryan, usando foreach em Stream-result -
Espero que isto ajude.
fonte
Kotlin tem
FileTreeWalk
para esse fim. Por exemplo:Produzirá uma lista de texto de todos os arquivos não pertencentes ao diretório em uma determinada raiz, um arquivo por linha com o caminho relativo à raiz e ao comprimento.
fonte
Outra maneira de fazer isso mesmo que alguém já forneça o Java 8 walk.
Este irá fornecer todos os arquivos recursivamente
fonte
Com base na resposta do empilhador. Aqui está uma solução trabalhando em JSP sem bibliotecas externas, para que você possa colocá-lo em praticamente qualquer lugar do seu servidor:
Então você apenas faz algo como:
fonte