J'ai cette fonction qui imprime le nom de tous les fichiers dans un répertoire de manière récursive. Le problème est que mon code est très lent car il doit accéder à un périphérique réseau distant à chaque itération.
Mon plan est de commencer par charger tous les fichiers du répertoire de manière récursive, puis de parcourir tous les fichiers avec l'expression régulière pour filtrer tous les fichiers que je ne veux pas. Quelqu'un a-t-il une meilleure suggestion?
public static printFnames(String sDir){
File[] faFiles = new File(sDir).listFiles();
for(File file: faFiles){
if(file.getName().matches("^(.*?)")){
System.out.println(file.getAbsolutePath());
}
if(file.isDirectory()){
printFnames(file.getAbsolutePath());
}
}
}
Ceci est juste un test plus tard, je n'utiliserai pas le code comme celui-ci, à la place je vais ajouter le chemin et la date de modification de chaque fichier qui correspond à une expression régulière avancée à un tableau.
Réponses:
En supposant qu'il s'agisse du code de production que vous allez écrire, je suggère d'utiliser la solution à ce genre de chose qui a déjà été résolue - Apache Commons IO , en particulier
FileUtils.listFiles()
. Il gère les répertoires imbriqués, les filtres (basés sur le nom, l'heure de modification, etc.).Par exemple, pour votre regex:
Collection files = FileUtils.listFiles( dir, new RegexFileFilter("^(.*?)"), DirectoryFileFilter.DIRECTORY );
Cela recherchera récursivement les fichiers correspondant à l'
^(.*?)
expression régulière, renvoyant les résultats sous forme de collection.Il convient de noter que ce ne sera pas plus rapide que de rouler votre propre code, cela fait la même chose - parcourir un système de fichiers en Java est juste lent. La différence est que la version Apache Commons ne contient aucun bogue.
la source
Files.walk(Paths.get("/etc")).filter(Files::isRegularFile).collect(Collectors.toList())
En Java 8, c'est un via 1-liner
Files.find()
avec une profondeur arbitrairement grande (par exemple999
) etBasicFileAttributes
deisRegularFile()
public static printFnames(String sDir) { Files.find(Paths.get(sDir), 999, (p, bfa) -> bfa.isRegularFile()).forEach(System.out::println); }
Pour ajouter plus de filtrage, améliorez le lambda, par exemple tous les fichiers jpg modifiés au cours des dernières 24 heures:
(p, bfa) -> bfa.isRegularFile() && p.getFileName().toString().matches(".*\\.jpg") && bfa.lastModifiedTime().toMillis() > System.currentMillis() - 86400000
la source
Il s'agit d'une méthode récursive très simple pour récupérer tous les fichiers d'une racine donnée.
Il utilise la classe Java 7 NIO Path.
private List<String> getFileNames(List<String> fileNames, Path dir) { try(DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) { for (Path path : stream) { if(path.toFile().isDirectory()) { getFileNames(fileNames, path); } else { fileNames.add(path.toAbsolutePath().toString()); System.out.println(path.getFileName()); } } } catch(IOException e) { e.printStackTrace(); } return fileNames; }
la source
Avec Java 7, un moyen plus rapide de parcourir une arborescence de répertoires a été introduit avec la fonctionnalité
Paths
etFiles
. Ils sont beaucoup plus rapides que laFile
méthode «ancienne» .Ce serait le code pour parcourir et vérifier les noms de chemin avec une expression régulière:
public final void test() throws IOException, InterruptedException { final Path rootDir = Paths.get("path to your directory where the walk starts"); // Walk thru mainDir directory Files.walkFileTree(rootDir, new FileVisitor<Path>() { // First (minor) speed up. Compile regular expression pattern only one time. private Pattern pattern = Pattern.compile("^(.*?)"); @Override public FileVisitResult preVisitDirectory(Path path, BasicFileAttributes atts) throws IOException { boolean matches = pattern.matcher(path.toString()).matches(); // TODO: Put here your business logic when matches equals true/false return (matches)? FileVisitResult.CONTINUE:FileVisitResult.SKIP_SUBTREE; } @Override public FileVisitResult visitFile(Path path, BasicFileAttributes mainAtts) throws IOException { boolean matches = pattern.matcher(path.toString()).matches(); // TODO: Put here your business logic when matches equals true/false return FileVisitResult.CONTINUE; } @Override public FileVisitResult postVisitDirectory(Path path, IOException exc) throws IOException { // TODO Auto-generated method stub return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFileFailed(Path path, IOException exc) throws IOException { exc.printStackTrace(); // If the root directory has failed it makes no sense to continue return path.equals(rootDir)? FileVisitResult.TERMINATE:FileVisitResult.CONTINUE; } }); }
la source
Le moyen rapide d'obtenir le contenu d'un répertoire à l'aide de Java 7 NIO:
import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.FileSystems; import java.nio.file.Path; ... Path dir = FileSystems.getDefault().getPath( filePath ); DirectoryStream<Path> stream = Files.newDirectoryStream( dir ); for (Path path : stream) { System.out.println( path.getFileName() ); } stream.close();
la source
Files.newDirectoryStream
peut lancer une IOException. Je suggère d'encapsuler cette ligne dans une instruction Java7 try-with-afin que le flux soit toujours fermé pour vous (exception ou non, sans avoir besoin d'unfinally
). Voir aussi ici: stackoverflow.com/questions/17739362/…L'interface de Java pour lire le contenu des dossiers du système de fichiers n'est pas très performante (comme vous l'avez découvert). JDK 7 corrige cela avec une interface complètement nouvelle pour ce genre de chose, qui devrait apporter des performances de niveau natif à ce type d'opérations.
Le problème principal est que Java effectue un appel système natif pour chaque fichier. Sur une interface à faible latence, ce n'est pas si grave - mais sur un réseau avec une latence même modérée, cela s'additionne vraiment. Si vous profilez votre algorithme ci-dessus, vous constaterez que la majeure partie du temps est consacrée à l'appel embêtant isDirectory () - c'est parce que vous subissez un aller-retour pour chaque appel à isDirectory (). La plupart des systèmes d'exploitation modernes peuvent fournir ce type d'informations lorsque la liste des fichiers / dossiers a été initialement demandée (par opposition à l'interrogation de chaque chemin de fichier individuel pour ses propriétés).
Si vous ne pouvez pas attendre JDK7, une stratégie pour résoudre cette latence est de passer au multi-thread et d'utiliser un ExecutorService avec un nombre maximum de threads pour effectuer votre récursivité. Ce n'est pas génial (vous devez gérer le verrouillage de vos structures de données de sortie), mais ce sera beaucoup plus rapide que de faire ce thread unique.
Dans toutes vos discussions sur ce genre de chose, je vous recommande fortement de comparer avec le mieux que vous puissiez faire en utilisant du code natif (ou même un script de ligne de commande qui fait à peu près la même chose). Dire qu'il faut une heure pour traverser une structure de réseau ne veut pas vraiment dire grand-chose. Nous dire que vous pouvez le faire nativement en 7 secondes, mais que cela prend une heure en Java, cela attirera l'attention des gens.
la source
cela fonctionnera très bien ... et son récursif
File root = new File("ROOT PATH"); for ( File file : root.listFiles()) { getFilesRecursive(file); } private static void getFilesRecursive(File pFile) { for(File files : pFile.listFiles()) { if(files.isDirectory()) { getFilesRecursive(files); } else { // do your thing // you can either save in HashMap and use it as // per your requirement } } }
la source
J'aime personnellement cette version de FileUtils. Voici un exemple qui trouve tous les mp3 ou flacs dans un répertoire ou l'un de ses sous-répertoires:
String[] types = {"mp3", "flac"}; Collection<File> files2 = FileUtils.listFiles(/path/to/your/dir, types , true);
la source
Cela fonctionnera bien
public void displayAll(File path){ if(path.isFile()){ System.out.println(path.getName()); }else{ System.out.println(path.getName()); File files[] = path.listFiles(); for(File dirOrFile: files){ displayAll(dirOrFile); } } }
la source
Cette fonction listera probablement tout le nom de fichier et son chemin depuis son répertoire et ses sous-répertoires.
public void listFile(String pathname) { File f = new File(pathname); File[] listfiles = f.listFiles(); for (int i = 0; i < listfiles.length; i++) { if (listfiles[i].isDirectory()) { File[] internalFile = listfiles[i].listFiles(); for (int j = 0; j < internalFile.length; j++) { System.out.println(internalFile[j]); if (internalFile[j].isDirectory()) { String name = internalFile[j].getAbsolutePath(); listFile(name); } } } else { System.out.println(listfiles[i]); } } }
la source
Java 8
public static void main(String[] args) throws IOException { Path start = Paths.get("C:\\data\\"); try (Stream<Path> stream = Files.walk(start, Integer.MAX_VALUE)) { List<String> collect = stream .map(String::valueOf) .sorted() .collect(Collectors.toList()); collect.forEach(System.out::println); } }
la source
Votre sentiment est faux. C'est ainsi que fonctionnent les systèmes de fichiers. Il n'y a pas de moyen plus rapide (sauf lorsque vous devez le faire à plusieurs reprises ou pour différents modèles, vous pouvez mettre en cache tous les chemins de fichiers en mémoire, mais vous devez ensuite gérer l'invalidation du cache, c'est-à-dire ce qui se passe lorsque des fichiers sont ajoutés / supprimés / renommés pendant l'application s'exécute).
la source
Juste pour que vous sachiez que isDirectory () est une méthode assez lente. Je trouve cela assez lent dans mon navigateur de fichiers. Je vais chercher dans une bibliothèque pour la remplacer par du code natif.
la source
Le moyen le plus efficace que j'ai trouvé pour traiter des millions de dossiers et de fichiers est de capturer la liste des répertoires via la commande DOS dans un fichier et de l'analyser. Une fois que vous avez analysé les données, vous pouvez effectuer des analyses et calculer des statistiques.
la source
import java.io.*; public class MultiFolderReading { public void checkNoOfFiles (String filename) throws IOException { File dir=new File(filename); File files[]=dir.listFiles();//files array stores the list of files for(int i=0;i<files.length;i++) { if(files[i].isFile()) //check whether files[i] is file or directory { System.out.println("File::"+files[i].getName()); System.out.println(); } else if(files[i].isDirectory()) { System.out.println("Directory::"+files[i].getName()); System.out.println(); checkNoOfFiles(files[i].getAbsolutePath()); } } } public static void main(String[] args) throws IOException { MultiFolderReading mf=new MultiFolderReading(); String str="E:\\file"; mf.checkNoOfFiles(str); } }
la source
Dans Guava, vous n'avez pas à attendre qu'une collection vous soit renvoyée, mais vous pouvez en fait parcourir les fichiers. Il est facile d'imaginer une
IDoSomethingWithThisFile
interface dans la signature de la fonction ci-dessous:public static void collectFilesInDir(File dir) { TreeTraverser<File> traverser = Files.fileTreeTraverser(); FluentIterable<File> filesInPostOrder = traverser.preOrderTraversal(dir); for (File f: filesInPostOrder) System.out.printf("File: %s\n", f.getPath()); }
TreeTraverser vous permet également de choisir entre différents styles de parcours.
la source
public class GetFilesRecursive { public static List <String> getFilesRecursively(File dir){ List <String> ls = new ArrayList<String>(); for (File fObj : dir.listFiles()) { if(fObj.isDirectory()) { ls.add(String.valueOf(fObj)); ls.addAll(getFilesRecursively(fObj)); } else { ls.add(String.valueOf(fObj)); } } return ls; } public static List <String> getListOfFiles(String fullPathDir) { List <String> ls = new ArrayList<String> (); File f = new File(fullPathDir); if (f.exists()) { if(f.isDirectory()) { ls.add(String.valueOf(f)); ls.addAll(getFilesRecursively(f)); } } else { ls.add(fullPathDir); } return ls; } public static void main(String[] args) { List <String> ls = getListOfFiles("/Users/srinivasab/Documents"); for (String file:ls) { System.out.println(file); } System.out.println(ls.size()); } }
la source
Un autre code optimisé
import java.io.File; import java.util.ArrayList; import java.util.List; public class GetFilesRecursive { public static List <String> getFilesRecursively(File dir){ List <String> ls = new ArrayList<String>(); if (dir.isDirectory()) for (File fObj : dir.listFiles()) { if(fObj.isDirectory()) { ls.add(String.valueOf(fObj)); ls.addAll(getFilesRecursively(fObj)); } else { ls.add(String.valueOf(fObj)); } } else ls.add(String.valueOf(dir)); return ls; } public static void main(String[] args) { List <String> ls = getFilesRecursively(new File("/Users/srinivasab/Documents")); for (String file:ls) { System.out.println(file); } System.out.println(ls.size()); } }
la source
Un autre exemple de liste de fichiers et de répertoires à l'aide de Java 8
filter
public static void main(String[] args) { System.out.println("Files!!"); try { Files.walk(Paths.get(".")) .filter(Files::isRegularFile) .filter(c -> c.getFileName().toString().substring(c.getFileName().toString().length()-4).contains(".jpg") || c.getFileName().toString().substring(c.getFileName().toString().length()-5).contains(".jpeg") ) .forEach(System.out::println); } catch (IOException e) { System.out.println("No jpeg or jpg files"); } System.out.println("\nDirectories!!\n"); try { Files.walk(Paths.get(".")) .filter(Files::isDirectory) .forEach(System.out::println); } catch (IOException e) { System.out.println("No Jpeg files"); } }
la source