J'essaie actuellement de supprimer récursivement un répertoire ... Curieusement, le morceau de code le plus court que j'ai pu trouver est la construction suivante, qui utilise une classe interne - ad-hoc et visitor pattern ...
Path rootPath = Paths.get("data/to-delete");
try {
Files.walkFileTree(rootPath, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
System.out.println("delete file: " + file.toString());
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
Files.delete(dir);
System.out.println("delete dir: " + dir.toString());
return FileVisitResult.CONTINUE;
}
});
} catch(IOException e){
e.printStackTrace();
}
Source: ici
Cela semble horriblement maladroit et prolixe, étant donné que les nouvelles API nio
suppriment tant d'encombrement et de passe-partout ...
Existe-t-il un moyen plus rapide de supprimer de manière forcée et récursive un répertoire?
Je recherche des méthodes natives pures Java 1.8, alors veuillez ne pas créer de lien vers des bibliothèques externes ...
Vous pouvez combiner NIO 2 et l’API Stream.
Path rootPath = Paths.get("/data/to-delete");
// before you copy and paste the snippet
// - read the post till the end
// - read the javadoc to understand what the code will do
//
// a) to follow softlinks (removes the linked file too) use
// Files.walk(rootPath, FileVisitOption.FOLLOW_LINKS)
//
// b) to not follow softlinks (removes only the softlink) use
// the snippet below
Files.walk(rootPath)
.sorted(Comparator.reverseOrder())
.map(Path::toFile)
.peek(System.out::println)
.forEach(File::delete);
Files.walk
- renvoie tous les fichiers/répertoires sous rootPath
, y compris.sorted
- trie la liste dans l'ordre inverse, le répertoire vient donc après les sous-répertoires et fichiers inclus.map
- mappe le Path
à File
.peek
- existe-t-il uniquement pour indiquer quelle entrée est traitée?.forEach
- appelle la méthode .delete()
sur chaque objet File
[~ # ~] éditer [~ # ~]
Voici quelques chiffres.
Le répertoire /data/to-delete
Contenait le rt.jar
Non compressé de jdk1.8.0_73 et une version récente de activemq .
files: 36,427
dirs : 4,143
size : 514 MB
Temps en millisecondes
int. SSD ext. USB3
NIO + Stream API 1,126 11,943
FileVisitor 1,362 13,561
Les deux versions ont été exécutées sans impression de noms de fichiers. Le facteur le plus limitant est le lecteur. Pas la mise en œuvre.
[~ # ~] éditer [~ # ~]
Quelques informations supplémentaires sur l’option FileVisitOption.FOLLOW_LINKS
.
Supposons la structure de fichiers et de répertoires suivante
/data/dont-delete/bar
/data/to-delete/foo
/data/to-delete/dont-delete -> ../dont-delete
En utilisant
Files.walk(rootPath, FileVisitOption.FOLLOW_LINKS)
suivra les liens symboliques et le fichier /tmp/dont_delete/bar
sera également supprimé.
En utilisant
Files.walk(rootPath)
ne suivra pas les liens symboliques et le fichier /tmp/dont_delete/bar
ne sera pas supprimé.
REMARQUE: N'utilisez jamais de code en tant que copier-coller sans comprendre ce qu'il fait.
La solution suivante n'a pas besoin de la conversion des objets Chemin en fichier:
Path rootPath = Paths.get("/data/to-delete");
final List<Path> pathsToDelete = Files.walk(rootPath).sorted(Comparator.reverseOrder()).collect(Collectors.toList());
for(Path path : pathsToDelete) {
Files.deleteIfExists(path);
}
Si vous devez utiliser uniquement Java 7 avec NIO
Path path = Paths.get("./target/logs");
Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc)
throws IOException {
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
});
Si vous avez déjà Spring Core dans le cadre de votre projet, voici un moyen simple de le faire:
FileSystemUtils.deleteRecursively(file);
Files.walk(pathToBeDeleted).sorted(Comparator.reverseOrder()).forEach(Files::delete);
Vous aurez besoin du modèle "essayer avec les ressources" pour fermer le flux si "l'élimination des ressources du système de fichiers en temps voulu est requise".
Aussi, probablement un commentaire importun, mais il serait beaucoup plus propre et plus lisible d’utiliser une bibliothèque. Avec le code dans une fonction partagée, cela ne prendra pas beaucoup d'espace. Toute personne qui consulte votre code doit valider que ce code effectue une suppression correcte, ce qui n’est nullement évident.
FileUtils.deleteDirectory
de Apache Commons IO supprime un répertoire de manière récursive.
Exemple:
Path pathToBeDeleted = TEMP_DIRECTORY.resolve(DIRECTORY_NAME);
boolean result = FileUtils.deleteDirectory(pathToBeDeleted.toFile());
Pour plus d'informations, voir Supprimer un répertoire de manière récursive en Java .