Question

Y at-il un moyen de supprimer des répertoires entiers récursive en Java?

Dans le cas normal, il est possible de supprimer un répertoire vide. Cependant, quand il vient de supprimer des répertoires entiers avec le contenu, il est aussi simple que cela plus.

Comment supprimer des répertoires entiers vous avec le contenu en Java?

Autres conseils

Avec Java 7, nous pouvons enfin faire avec détection de symlink fiable. (je ne considère pas le Communes- d'Apache io avoir fiable détection symlink à ce moment, car il ne gère pas les liens créés avec sous Windows mklink.)

Pour l'amour de l'histoire, voici une réponse pré-Java 7, suit les liens symboliques.

void delete(File f) throws IOException {
  if (f.isDirectory()) {
    for (File c : f.listFiles())
      delete(c);
  }
  if (!f.delete())
    throw new FileNotFoundException("Failed to delete file: " + f);
}

En Java 7+, vous pouvez utiliser la classe Files . Le code est très simple:

Path directory = Paths.get("/tmp");
Files.walkFileTree(directory, 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;
   }
});

Java 7 a ajouté le support pour les répertoires à pied avec la manipulation symlink:

import java.nio.file.*;

public static void removeRecursive(Path path) throws IOException
{
    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 visitFileFailed(Path file, IOException exc) throws IOException
        {
            // try to delete the file anyway, even if its attributes
            // could not be read, since delete-only access is
            // theoretically possible
            Files.delete(file);
            return FileVisitResult.CONTINUE;
        }

        @Override
        public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException
        {
            if (exc == null)
            {
                Files.delete(dir);
                return FileVisitResult.CONTINUE;
            }
            else
            {
                // directory iteration failed; propagate exception
                throw exc;
            }
        }
    });
}

I l'utiliser comme une solution de repli à partir de méthodes spécifiques à la plate-forme (dans ce non testé code ):

public static void removeDirectory(Path directory) throws IOException
{
    // does nothing if non-existent
    if (Files.exists(directory))
    {
        try
        {
            // prefer OS-dependent directory removal tool
            if (SystemUtils.IS_OS_WINDOWS)
                Processes.execute("%ComSpec%", "/C", "RD /S /Q \"" + directory + '"');
            else if (SystemUtils.IS_OS_UNIX)
                Processes.execute("/bin/rm", "-rf", directory.toString());
        }
        catch (ProcessExecutionException | InterruptedException e)
        {
            // fallback to internal implementation on error
        }

        if (Files.exists(directory))
            removeRecursive(directory);
    }
}

(SystemUtils est de Apache Commons Lang . Les processus est privé, mais son comportement devrait être évident.)

Une solution-liner (Java8) pour supprimer tous les fichiers et répertoires, y compris récursive répertoire de départ:

Files.walk(Paths.get("c:/dir_to_delete/"))
                .map(Path::toFile)
                .sorted((o1, o2) -> -o1.compareTo(o2))
                .forEach(File::delete);

Nous utilisons un comparateur pour l'ordre inverse, sinon File :: supprimer ne sera pas en mesure de supprimer le répertoire éventuellement non vide. Donc, si vous voulez conserver les répertoires et seulement supprimer des fichiers simplement supprimer le comparateur dans Sorted () ou supprimer le tri complètement et ajouter le filtre de fichiers:

Files.walk(Paths.get("c:/dir_to_delete/"))
                .filter(Files::isRegularFile)
                .map(Path::toFile)
                .forEach(File::delete);

Je viens de voir est plus ou moins ma solution la même que celle erickson, juste emballé comme une méthode statique. Laissez tomber ce quelque part, il est beaucoup de poids plus léger que l'installation de tous Apache Commons pour quelque chose qui (comme vous pouvez le voir) est tout à fait simple.

public class FileUtils {
    /**
     * By default File#delete fails for non-empty directories, it works like "rm". 
     * We need something a little more brutual - this does the equivalent of "rm -r"
     * @param path Root File Path
     * @return true iff the file and all sub files/directories have been removed
     * @throws FileNotFoundException
     */
    public static boolean deleteRecursive(File path) throws FileNotFoundException{
        if (!path.exists()) throw new FileNotFoundException(path.getAbsolutePath());
        boolean ret = true;
        if (path.isDirectory()){
            for (File f : path.listFiles()){
                ret = ret && deleteRecursive(f);
            }
        }
        return ret && path.delete();
    }
}

Une solution avec une pile et sans méthodes récursives:

File dir = new File("/path/to/dir");
File[] currList;
Stack<File> stack = new Stack<File>();
stack.push(dir);
while (! stack.isEmpty()) {
    if (stack.lastElement().isDirectory()) {
        currList = stack.lastElement().listFiles();
        if (currList.length > 0) {
            for (File curr: currList) {
                stack.push(curr);
            }
        } else {
            stack.pop().delete();
        }
    } else {
        stack.pop().delete();
    }
}

Goyave avait Files.deleteRecursively(File) soutenu jusqu'à ce que Goyave 9 .

Guava 10 :

  

Obsolète. Cette méthode souffre de mauvaise détection de symlink et conditions course. Cette fonctionnalité peut être supportée de façon appropriée seulement par les bombardements à une commande du système d'exploitation tel que rm -rf ou del /s. Cette méthode est prévue pour être retiré de goyave goyave version 11.0.

Par conséquent, il n'y a pas cette méthode dans Goyave 11 .

Si vous avez Spring, vous pouvez utiliser FileSystemUtils.deleteRecursively :

import org.springframework.util.FileSystemUtils;

boolean success = FileSystemUtils.deleteRecursively(new File("directory"));
for(Path p : Files.walk(directoryToDelete).
        sorted((a, b) -> b.compareTo(a)). // reverse; files before dirs
        toArray(Path[]::new))
{
    Files.delete(p);
}

Ou si vous voulez gérer le IOException:

Files.walk(directoryToDelete).
    sorted((a, b) -> b.compareTo(a)). // reverse; files before dirs
    forEach(p -> {
        try { Files.delete(p); }
        catch(IOException e) { /* ... */ }
      });
public void deleteRecursive(File path){
    File[] c = path.listFiles();
    System.out.println("Cleaning out folder:" + path.toString());
    for (File file : c){
        if (file.isDirectory()){
            System.out.println("Deleting file:" + file.toString());
            deleteRecursive(file);
            file.delete();
        } else {
            file.delete();
        }
    }
    path.delete();
}
static public void deleteDirectory(File path) 
{
    if (path == null)
        return;
    if (path.exists())
    {
        for(File f : path.listFiles())
        {
            if(f.isDirectory()) 
            {
                deleteDirectory(f);
                f.delete();
            }
            else
            {
                f.delete();
            }
        }
        path.delete();
    }
}

Deux manières d'échouer avec lien symbolique et le code ci-dessus ... et ne savent pas la solution.

Way # 1

Exécuter ce pour créer un test:

echo test > testfile
mkdir dirtodelete
ln -s badlink dirtodelete/badlinktodelete

Ici, vous voyez votre fichier de test et répertoire test:

$ ls testfile dirtodelete
testfile

dirtodelete:
linktodelete

Ensuite, exécutez vos commons-io deleteDirectory (). Il se bloque en disant que le fichier est introuvable. Je ne sais pas ce que les autres exemples font ici. La commande de Linux serait simplement supprimer le lien et rm -r dans le répertoire serait également.

Exception in thread "main" java.io.FileNotFoundException: File does not exist: /tmp/dirtodelete/linktodelete

Way # 2

Exécuter ce pour créer un test:

mkdir testdir
echo test > testdir/testfile
mkdir dirtodelete
ln -s ../testdir dirtodelete/dirlinktodelete

Ici, vous voyez votre fichier de test et répertoire test:

$ ls dirtodelete testdir
dirtodelete:
dirlinktodelete

testdir:
testfile

Ensuite, exécutez vos commons-io deleteDirectory () ou le peuple de code exemple affiché. Il supprime non seulement le répertoire, mais votre testfile qui est en dehors du répertoire en cours de suppression. (Il déréférence le répertoire implicitement, et supprime le contenu). rm -r supprimerais le seul lien. Vous devez utiliser quelque chose comme ceci supprimer les fichiers déréférencés:. "Trouver -L dirtodelete -type f -exec rm {} \;"

$ ls dirtodelete testdir
ls: cannot access dirtodelete: No such file or directory
testdir:

Vous pouvez utiliser:

org.apache.commons.io.FileUtils.deleteQuietly(destFile);

supprime un fichier, lancer jamais une exception. Si le fichier est un répertoire, supprimez-le et tous les sous-répertoires. La différence entre File.Delete () et cette méthode sont les suivantes: Un répertoire à supprimer ne doit pas être vide. Aucune exception ne sont jetés lorsqu'un fichier ou un répertoire ne peuvent pas être supprimés.

Une solution qui gère exception conformément à l'approche qu'une exception lancée à partir d'une méthode doit toujours décrire cette méthode a essayé (et échoué) à faire:

private void deleteRecursive(File f) throws Exception {
    try {
        if (f.isDirectory()) {
            for (File c : f.listFiles()) {
                deleteRecursive(c);
            }
        }
        if (!f.delete()) {
            throw new Exception("Delete command returned false for file: " + f);
        }
    } 
    catch (Exception e) {
        throw new Exception("Failed to delete the folder: " + f, e);
    }
}

Dans les projets existants, je dois créer un code Java natif. Je crée ce code similaire au code Paulitex. Voir que:

public class FileHelper {

   public static boolean delete(File fileOrFolder) {
      boolean result = true;
      if(fileOrFolder.isDirectory()) {
         for (File file : fileOrFolder.listFiles()) {
            result = result && delete(file);
         }
      }
      result = result && fileOrFolder.delete();
      return result;
   } 
}

Et le test unitaire:

public class FileHelperTest {

    @Before
    public void setup() throws IOException {
       new File("FOLDER_TO_DELETE/SUBFOLDER").mkdirs();
       new File("FOLDER_TO_DELETE/SUBFOLDER_TWO").mkdirs();
       new File("FOLDER_TO_DELETE/SUBFOLDER_TWO/TEST_FILE.txt").createNewFile();
    }

    @Test
    public void deleteFolderWithFiles() {
       File folderToDelete = new File("FOLDER_TO_DELETE");
       Assert.assertTrue(FileHelper.delete(folderToDelete));
       Assert.assertFalse(new File("FOLDER_TO_DELETE").exists());
    }

}

Voici une méthode principale bare os qui accepte un argument de ligne de commande, vous devrez peut-être ajouter votre propre erreur de vérification ou de la moisissure à la façon dont bon vous semble.

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

public class DeleteFiles {

/**
 * @param intitial arguments take in a source to read from and a 
 * destination to read to
 */
    public static void main(String[] args)
                     throws FileNotFoundException,IOException {
        File src = new File(args[0]);
        if (!src.exists() ) {
            System.out.println("FAILURE!");
        }else{
            // Gathers files in directory
            File[] a = src.listFiles();
            for (int i = 0; i < a.length; i++) {
                //Sends files to recursive deletion method
                fileDelete(a[i]);
            }
            // Deletes original source folder
            src.delete();
            System.out.println("Success!");
        }
    }

    /**
     * @param srcFile Source file to examine
     * @throws FileNotFoundException if File not found
     * @throws IOException if File not found
     */
    private static void fileDelete(File srcFile)
                     throws FileNotFoundException, IOException {
        // Checks if file is a directory
        if (srcFile.isDirectory()) {
            //Gathers files in directory
            File[] b = srcFile.listFiles();
            for (int i = 0; i < b.length; i++) {
                //Recursively deletes all files and sub-directories
                fileDelete(b[i]);
            }
            // Deletes original sub-directory file
            srcFile.delete();
        } else {
            srcFile.delete();
        }
    }
}

J'espère que cela!

Ci-dessous le code supprimer récursive tous les contenus dans un dossier donné.

boolean deleteDirectory(File directoryToBeDeleted) {
    File[] allContents = directoryToBeDeleted.listFiles();
    if (allContents != null) {
        for (File file : allContents) {
            deleteDirectory(file);
        }
    }
    return directoryToBeDeleted.delete();
}

Peut-être une solution à ce problème pourrait être ré-écrire la méthode de suppression de la classe de fichier en utilisant le code de la réponse de erickson:

public class MyFile extends File {

  ... <- copy constructor

  public boolean delete() {
    if (f.isDirectory()) {
      for (File c : f.listFiles()) {
        return new MyFile(c).delete();
      }
    } else {
        return f.delete();
    }
  }
}

Sans Commons IO et

public static void deleteRecursive(File path){
            path.listFiles(new FileFilter() {
                @Override
                public boolean accept(File pathname) {
                    if (pathname.isDirectory()) {
                        pathname.listFiles(this);
                        pathname.delete();
                    } else {
                        pathname.delete();
                    }
                    return false;
                }
            });
            path.delete();
        }

Bien que les fichiers peuvent facilement être supprimés à l'aide File.Delete (), les répertoires doivent être vides à supprimer. Utilisez récursivité pour le faire facilement. Par exemple:

public static void clearFolders(String[] args) {
        for(String st : args){
            File folder = new File(st);
            if (folder.isDirectory()) {
                File[] files = folder.listFiles();
                if(files!=null) { 
                    for(File f: files) {
                        if (f.isDirectory()){
                            clearFolders(new String[]{f.getAbsolutePath()});
                            f.delete();
                        } else {
                            f.delete();
                        }
                    }
                }
            }
        }
    }

i codé cette routine qui a 3 critères de sécurité pour une utilisation plus sûre.

package ch.ethz.idsc.queuey.util;

import java.io.File;
import java.io.IOException;

/** recursive file/directory deletion
 * 
 * safety from erroneous use is enhanced by three criteria
 * 1) checking the depth of the directory tree T to be deleted
 * against a permitted upper bound "max_depth"
 * 2) checking the number of files to be deleted #F
 * against a permitted upper bound "max_count"
 * 3) if deletion of a file or directory fails, the process aborts */
public final class FileDelete {
    /** Example: The command
     * FileDelete.of(new File("/user/name/myapp/recordings/log20171024"), 2, 1000);
     * deletes given directory with sub directories of depth of at most 2,
     * and max number of total files less than 1000. No files are deleted
     * if directory tree exceeds 2, or total of files exceed 1000.
     * 
     * abort criteria are described at top of class
     * 
     * @param file
     * @param max_depth
     * @param max_count
     * @return
     * @throws Exception if criteria are not met */
    public static FileDelete of(File file, int max_depth, int max_count) throws IOException {
        return new FileDelete(file, max_depth, max_count);
    }

    // ---
    private final File root;
    private final int max_depth;
    private int removed = 0;

    /** @param root file or a directory. If root is a file, the file will be deleted.
     *            If root is a directory, the directory tree will be deleted.
     * @param max_depth of directory visitor
     * @param max_count of files to delete
     * @throws IOException */
    private FileDelete(final File root, final int max_depth, final int max_count) throws IOException {
        this.root = root;
        this.max_depth = max_depth;
        // ---
        final int count = visitRecursively(root, 0, false);
        if (count <= max_count) // abort criteria 2)
            visitRecursively(root, 0, true);
        else
            throw new IOException("more files to be deleted than allowed (" + max_count + "<=" + count + ") in " + root);
    }

    private int visitRecursively(final File file, final int depth, final boolean delete) throws IOException {
        if (max_depth < depth) // enforce depth limit, abort criteria 1)
            throw new IOException("directory tree exceeds permitted depth");
        // ---
        int count = 0;
        if (file.isDirectory()) // if file is a directory, recur
            for (File entry : file.listFiles())
                count += visitRecursively(entry, depth + 1, delete);
        ++count; // count file as visited
        if (delete) {
            final boolean deleted = file.delete();
            if (!deleted) // abort criteria 3)
                throw new IOException("cannot delete " + file.getAbsolutePath());
            ++removed;
        }
        return count;
    }

    public int deletedCount() {
        return removed;
    }

    public void printNotification() {
        int count = deletedCount();
        if (0 < count)
            System.out.println("deleted " + count + " file(s) in " + root);
    }
}

Eh bien, supposons un exemple,

import java.io.File;
import java.io.IOException;

public class DeleteDirectory
{
   private static final String folder = "D:/project/java";

   public static void main(String[] args) throws IOException
   {
      File fl = new File(folder);
      if(!fl.exists()) // checking if directory exists
      {
         System.out.println("Sorry!! directory doesn't exist.");
      }
      else
      {
         DeleteDirectory dd = new DeleteDirectory();
         dd.deleteDirectory(fl);
      }
   }

   public void deleteDirectory(File file) throws IOException
   {
      if(file.isDirectory())
      {
         if(file.list().length == 0)
         { 
            deleteEmptyDirectory(file); // here if directory is empty delete we are deleting
         }
         else
         {
            File fe[] = file.listFiles();
            for(File deleteFile : fe)
            {
               deleteDirectory(deleteFile); // recursive call
            }
            if(file.list().length == 0)
            {
               deleteEmptyDirectory(file);
            }
         }
      }
      else
      {
         file.delete();
         System.out.println("File deleted : " + file.getAbsolutePath());
      }
   }

   private void deleteEmptyDirectory(File fi)
   {
      fi.delete();
      System.out.println("Directory deleted : " + fi.getAbsolutePath());
   }
}

Pour plus d'informations, consulter ci-dessous les ressources

Supprimer répertoire

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top