Je viens de terminer les résultats des tests qui fournissent des tests de performances pour de nombreuses réponses. Sans surprise, toutes les réponses basées sur NIO fonctionnent mieux. La réponse commune-io est clairement la moins performante avec plus de deux fois la longueur de la course.
Brett Ryan
2
Java8: Files.walk?
Benj
Réponses:
327
Java 8 fournit un joli flux pour traiter tous les fichiers d'une arborescence.
Cela fournit un moyen naturel de parcourir les fichiers. Puisqu'il s'agit d'un flux, vous pouvez effectuer toutes les belles opérations de flux sur le résultat, telles que la limite, le regroupement, le mappage, la sortie anticipée, etc.
MISE À JOUR : Je pourrais souligner qu'il existe également Files.find qui prend un BiPredicate qui pourrait être plus efficace si vous devez vérifier les attributs de fichier.
Notez que bien que JavaDoc élude que cette méthode pourrait être plus efficace que Files.walk, elle est effectivement identique, la différence de performances peut être observée si vous récupérez également des attributs de fichier dans votre filtre. En fin de compte, si vous devez filtrer les attributs, utilisez Files.find , sinon utilisez Files.walk , principalement parce qu'il y a des surcharges et c'est plus pratique.
Un de ces exemples qui peuvent montrer la magie de la programmation fonctionnelle même pour les débutants.
Johnny
2
Comment les performances de cette comparaison avec les méthodes pré-java 8? La traversée de mon répertoire actuel est trop lente et je cherche quelque chose qui va l'accélérer.
Sridhar Sarnobat
1
J'écris quelques tests contenant la plupart des variantes dans les réponses fournies. Jusqu'à présent, il semble que l'utilisation Files.walkavec un flux parallèle soit la meilleure, suivie de près par Files.walkFileTreelaquelle n'est que légèrement plus lente. La réponse acceptée en utilisant commons-io est de loin la plus lente de mes tests à être 4 fois plus lente.
Brett Ryan
1
@BrettRyan, j'ai essayé votre solution mais je reçois une exception Exception in thread "main" java.io.UncheckedIOException: java.nio.file.AccessDeniedException. Comment pourrais-je le corriger
Kachna
5
Comment puis-je obtenir une liste réelle de fichiers à partir de cela?
Edit: Vous pouvez vérifier ici pour un benchmark des différentes approches. Il semble que l'approche commune-io soit lente, alors choisissez quelques-unes des plus rapides d'ici (si cela est important)
FYI / TLDR: si vous voulez simplement lister tous les fichiers récursivement sans filtrage, faites FileUtils.listFiles(dir, TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE), où direst un objet File qui pointe vers le répertoire de base.
andronikus
2
Vous voudrez peut-être envisager d'utiliser listFilesAndDirs(), car listFiles()ne renvoie pas de dossiers vides.
schnatterer
1
@MikeFHay En regardant le code FileUtils, je pense que ce serait le cas FileUtils.listFiles(dir, true, true). using FileUtils.listFiles(dir, null, true)lèvera une exception, tandis que FileUtils.listFiles(dir, true, null)listera tous les fichiers sans regarder dans les sous-répertoires.
ocramot
Que diriez-vous d'une bibliothèque native JDK? Je peux implémenter cela facilement mais je serais simplement C&P d'autres endroits
Christian Bongiorno
1
Je suis en train de mettre ensemble des tests, mais jusqu'à présent, cela semble fonctionner 4 fois plus lentement que celui d'utiliser des alternatives JDK8 ou JDK7. Les liens symboliques s'avèrent également problématiques avec cette approche, en particulier lorsqu'ils sont liés à des répertoires situés plus haut dans l'arborescence, ce qui empêche la méthode de revenir, cela peut être évité en manipulant le filtre, mais malheureusement, les liens symboliques eux-mêmes ne sont pas visités même si un fichier.
Brett Ryan
138
// Prêt à courir
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:\\");}}
Gardez juste à l'esprit que pour les liens symboliques qui pointent vers un chemin plus haut dans la hiérarchie des chemins, la méthode ne se terminera jamais. Considérez un chemin d'accès avec un lien symbolique qui pointe vers -> ..
Brett Ryan
2
Il s'agit essentiellement d'une mauvaise implémentation de Files.walkFileTree. Je recommanderais que les gens regardent FIles.walkFileTree au lieu d'essayer de le faire rouler vous-même ... Il a la gestion du problème exact @BrettRyan l'a indiqué.
Tyler Nichols
Merci d'avoir inclus import java.io.File ;. De nombreux exemples oublient d'inclure les éléments d'espace de noms ou même les éléments de type de données, faisant de l'exemple un point de départ pour un voyage de découverte. Ici, cet exemple est prêt à fonctionner. Merci.
barrypicker
Le chemin peut varier selon l'emplacement du fichier Filewalker. Utilisez "/", "./"ou "../"pour le répertoire racine, le répertoire de travail actuel et le répertoire parent, respectivement
Si vous fournissez un point de départ et un visiteur de fichier, il invoquera diverses méthodes sur le visiteur de fichier pendant qu'il parcourt le fichier dans l'arborescence de fichiers. Nous nous attendons à ce que les utilisateurs l'utilisent s'ils développent une copie récursive, un déplacement récursif, une suppression récursive ou une opération récursive qui définit des autorisations ou effectue une autre opération sur chacun des fichiers.
publicvoid list(File file){System.out.println(file.getName());File[] children = file.listFiles();for(File child : children){
list(child);}}
Le System.out.println est juste là pour indiquer de faire quelque chose avec le fichier. il n'est pas nécessaire de faire la différence entre les fichiers et les répertoires, car un fichier normal n'aura simplement aucun enfant.
S'il vous plaît! laissez l'appelant initialiser la liste des fichiers afin qu'il n'ait pas à vérifier sa nullité à chaque fois. Si vous souhaitez créer une deuxième méthode (publique) qui crée la liste, appelle cette méthode interne et renvoie la liste complète.
helios
1
peu importe. un chèque nul n'est pas très cher, commodité + préférence personnelle à part je pense qu'il obtiendra le point.
pstanton
Pouvez-vous expliquer un peu plus verbalement?
2013
8
Je pense que cela devrait faire le travail:
File dir =newFile(dirname);String[] files = dir.list();
De cette façon, vous avez des fichiers et des répertoires. Utilisez maintenant la récursivité et faites de même pour les répertoires (la Fileclasse a une isDirectory()méthode).
Outre la traversée récursive, on peut également utiliser une approche basée sur les visiteurs.
Le code ci-dessous utilise l'approche basée sur les visiteurs pour la traversée. On s'attend à ce que l'entrée du programme soit le répertoire racine à parcourir.
La réponse acceptée est excellente, mais elle tombe en panne lorsque vous voulez faire des E / S à l'intérieur du lambda.
Voici ce que vous pouvez faire si votre action déclare des IOExceptions.
Vous pouvez traiter le flux filtré comme un Iterable, puis effectuer votre action dans une boucle régulière pour chaque. De cette façon, vous n'avez pas à gérer les exceptions à l'intérieur d'un 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);}}
Publier cet exemple, car j'ai eu du mal à comprendre comment passer le paramètre de nom de fichier dans l'exemple n ° 1 donné par Bryan, en utilisant foreach sur Stream-result -
Produira une liste de textes de tous les fichiers non-répertoires sous une racine donnée, un fichier par ligne avec le chemin relatif à la racine et la longueur.
Basé sur la réponse de l'empileur. Voici une solution fonctionnant dans JSP sans aucune bibliothèque externe afin que vous puissiez la mettre presque n'importe où sur votre serveur:
<!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()+"/";%>
Bien que cela fonctionne probablement, la question concerne la navigation dans les fichiers, pas le rendu des fichiers parcourus. Mieux exposer votre algorithme en tant que tel, il n'est pas recommandé d'intégrer la logique métier dans une JSP.
Samuel Kerrien
Cela dépend de ce que vous faites. Dans une application de taille entreprise, vous avez absolument raison. Si vous avez juste besoin de cela en tant que point d'accès à une liste simple et autonome, cela est parfaitement bien.
Réponses:
Java 8 fournit un joli flux pour traiter tous les fichiers d'une arborescence.
Cela fournit un moyen naturel de parcourir les fichiers. Puisqu'il s'agit d'un flux, vous pouvez effectuer toutes les belles opérations de flux sur le résultat, telles que la limite, le regroupement, le mappage, la sortie anticipée, etc.
MISE À JOUR : Je pourrais souligner qu'il existe également Files.find qui prend un BiPredicate qui pourrait être plus efficace si vous devez vérifier les attributs de fichier.
Notez que bien que JavaDoc élude que cette méthode pourrait être plus efficace que Files.walk, elle est effectivement identique, la différence de performances peut être observée si vous récupérez également des attributs de fichier dans votre filtre. En fin de compte, si vous devez filtrer les attributs, utilisez Files.find , sinon utilisez Files.walk , principalement parce qu'il y a des surcharges et c'est plus pratique.
TESTS : Comme demandé, j'ai fourni une comparaison des performances de la plupart des réponses. Découvrez le projet Github qui contient des résultats et un cas de test .
la source
Files.walk
avec un flux parallèle soit la meilleure, suivie de près parFiles.walkFileTree
laquelle n'est que légèrement plus lente. La réponse acceptée en utilisant commons-io est de loin la plus lente de mes tests à être 4 fois plus lente.Exception in thread "main" java.io.UncheckedIOException: java.nio.file.AccessDeniedException
. Comment pourrais-je le corrigerFileUtils ont
iterateFiles
etlistFiles
méthodes. Essayez-les. (de commons-io )Edit: Vous pouvez vérifier ici pour un benchmark des différentes approches. Il semble que l'approche commune-io soit lente, alors choisissez quelques-unes des plus rapides d'ici (si cela est important)
la source
FileUtils.listFiles(dir, TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE)
, oùdir
est un objet File qui pointe vers le répertoire de base.listFilesAndDirs()
, carlistFiles()
ne renvoie pas de dossiers vides.FileUtils.listFiles(dir, true, true)
. usingFileUtils.listFiles(dir, null, true)
lèvera une exception, tandis queFileUtils.listFiles(dir, true, null)
listera tous les fichiers sans regarder dans les sous-répertoires.// Prêt à courir
la source
-> .
."/"
,"./"
ou"../"
pour le répertoire racine, le répertoire de travail actuel et le répertoire parent, respectivementJava 7
auraa Files.walkFileTree :Il existe désormais un didacticiel Oracle complet sur cette question .
la source
Aucune bibliothèque externe requise.
Renvoie une collection pour que vous puissiez en faire ce que vous voulez après l'appel.
la source
J'irais avec quelque chose comme:
Le System.out.println est juste là pour indiquer de faire quelque chose avec le fichier. il n'est pas nécessaire de faire la différence entre les fichiers et les répertoires, car un fichier normal n'aura simplement aucun enfant.
la source
listFiles()
: "Si ce nom de chemin abstrait ne désigne pas un répertoire, alors cette méthode revientnull
."Je préfère utiliser une file d'attente à la récursivité pour ce type de traversion simple:
la source
écrivez-le vous-même en utilisant une récursivité simple:
la source
Je pense que cela devrait faire le travail:
De cette façon, vous avez des fichiers et des répertoires. Utilisez maintenant la récursivité et faites de même pour les répertoires (la
File
classe a uneisDirectory()
méthode).la source
Avec Java 7, vous pouvez utiliser la classe suivante:
la source
Dans Java 8, nous pouvons désormais utiliser l'utilitaire Fichiers pour parcourir une arborescence de fichiers. Très simple.
la source
Ce code est prêt à fonctionner
la source
Outre la traversée récursive, on peut également utiliser une approche basée sur les visiteurs.
Le code ci-dessous utilise l'approche basée sur les visiteurs pour la traversée. On s'attend à ce que l'entrée du programme soit le répertoire racine à parcourir.
la source
Vous pouvez utiliser le code ci-dessous pour obtenir une liste de fichiers d'un dossier ou répertoire spécifique de manière récursive.
la source
La réponse acceptée est excellente, mais elle tombe en panne lorsque vous voulez faire des E / S à l'intérieur du lambda.
Voici ce que vous pouvez faire si votre action déclare des IOExceptions.
Vous pouvez traiter le flux filtré comme un
Iterable
, puis effectuer votre action dans une boucle régulière pour chaque. De cette façon, vous n'avez pas à gérer les exceptions à l'intérieur d'un lambda.Trouvé cette astuce ici: https://stackoverflow.com/a/32668807/1207791
la source
BFS non récursif avec une seule liste (un exemple particulier est la recherche de fichiers * .eml):
la source
Ma version (bien sûr j'aurais pu utiliser la promenade intégrée dans Java 8 ;-)):
la source
Voici une solution simple mais parfaitement fonctionnelle utilisant
recursion
:la source
la source
Je suis venu avec ceci pour imprimer tous les fichiers / noms de fichiers récursivement.
la source
L'exemple génère des fichiers * .csv dans le répertoire de recherche récursive des sous-répertoires à l'aide de Files.find () à partir de java.nio:
Publier cet exemple, car j'ai eu du mal à comprendre comment passer le paramètre de nom de fichier dans l'exemple n ° 1 donné par Bryan, en utilisant foreach sur Stream-result -
J'espère que cela t'aides.
la source
Kotlin a
FileTreeWalk
à cet effet. Par exemple:Produira une liste de textes de tous les fichiers non-répertoires sous une racine donnée, un fichier par ligne avec le chemin relatif à la racine et la longueur.
la source
Vous pouvez également le faire même si quelqu'un fournit déjà Java 8 à pied.
Celui-ci vous fournira tous les fichiers récursivement
la source
Basé sur la réponse de l'empileur. Voici une solution fonctionnant dans JSP sans aucune bibliothèque externe afin que vous puissiez la mettre presque n'importe où sur votre serveur:
Ensuite, vous faites simplement quelque chose comme:
la source