Delete directories recursively in Java

274,443

Solution 1

You should check out Apache's commons-io. It has a FileUtils class that will do what you want.

FileUtils.deleteDirectory(new File("directory"));

Solution 2

With Java 7, we can finally do this with reliable symlink detection. (I don't consider Apache's commons-io to have reliable symlink detection at this time, as it doesn't handle links on Windows created with mklink.)

For the sake of history, here's a pre-Java 7 answer, which follows symlinks.

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);
}

Solution 3

In Java 7+ you can use Files class. Code is very 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;
   }
});

Solution 4

One-liner solution (Java8) to delete all files and directories recursively including starting directory:

try (var dirStream = Files.walk(Paths.get("c:/dir_to_delete/"))) {
    dirStream
        .map(Path::toFile)
        .sorted(Comparator.reverseOrder())
        .forEach(File::delete);
}

We use a comparator for reversed order, otherwise File::delete won't be able to delete possibly non-empty directory. So, if you want to keep directories and only delete files just remove the comparator in sorted() or remove sorting completely and add files filter:

try (var dirStream = Files.walk(Paths.get("c:/dir_to_delete/"))) {
    dirStream
        .filter(Files::isRegularFile)
        .map(Path::toFile)
        .forEach(File::delete);
}

Solution 5

Java 7 added support for walking directories with symlink handling:

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 use this as a fallback from platform-specific methods (in this untested 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 is from Apache Commons Lang. Processes is private but its behavior should be obvious.)

Share:
274,443
paweloque
Author by

paweloque

My current projects: https://orbit7.ch https://gobugfree.com Follow me on Twitter: @paweloque

Updated on July 08, 2022

Comments

  • paweloque
    paweloque almost 2 years

    Is there a way to delete entire directories recursively in Java?

    In the normal case it is possible to delete an empty directory. However when it comes to deleting entire directories with contents, it is not that simple anymore.

    How do you delete entire directories with contents in Java?

  • paweloque
    paweloque about 15 years
    I agree, what you write as an answer is a good solution. However I'd like the File.delete() method handle this case automatically.
  • Ben S
    Ben S about 15 years
    File.delete() does not have that functionality.
  • brady
    brady about 15 years
    I think it's implemented as it is to mimic the behavior of most command shell utilities like "rm", "rmdir", and "del". Of the two alternatives, the current implementation definitely minimizes the overall surprise (and anger) potential. It isn't going to change.
  • Eddie
    Eddie about 15 years
    Generally, the only Java JRE packages I see extended are from Swing. Usually, extending other classes such as java.io.File is a bad idea, as it has the possibility to cause things to act in unexpected ways.
  • Lawrence Dol
    Lawrence Dol about 15 years
    @Erickson: Isn't FileNotFoundException a poor exception for a delete failure? If the file is truly no longer there, it must have already been deleted, which means that, semantically, the delete did not fail - it had nothing to do. And if it failed for some other reason, it was not because the file was not found.
  • brady
    brady about 15 years
    @Software Monkey: I just picked FileNotFoundException because that's what is used for pretty much every file-oriented problem in java.io... permissions, etc. Not great, but the IOException hierarchy is seriously lacking. I hope the NIO2 library does a lot better here.
  • Rahul.B
    Rahul.B over 12 years
    Too bad. Shelling out seems a little crude and not portable. If the Apache commons version works properly, then presumably it's not impossible to implement.
  • orip
    orip almost 12 years
    @andrew The Apache Commons implementation should have similar problems to those that cause Guava to remove their implementation, see code.google.com/p/guava-libraries/issues/detail?id=365
  • Nathan Osman
    Nathan Osman about 11 years
    +1 for using a stack. This will work with directories that contain deep levels of nested subdirectories while the other stack-based approaches will fail.
  • Hakanai
    Hakanai about 11 years
    I do find one problem with Files.walkFileTree - it is insufficient for implementing a version of recursive delete where you keep deleting files until you run out of options. It is adequate for a fail-fast version, but fail-fast is not always what you want (e.g. if you're cleaning up temp files, you want delete-now, not fail-fast.)
  • Trevor Robinson
    Trevor Robinson about 11 years
    I don't see why that is true. You can handle errors however you want -- you're not required to fail fast. The only issue I could foresee is that it might not handle new files being created during the walk of the current directory, but that is a unique situation better suited to a custom solution.
  • Hakanai
    Hakanai about 11 years
    If you suppress the error from visitFile and call walkFileTree on a single file which fails, you get no error (so visitFile must propagate any error which occurs.) If you're deleting a directory and fail to delete one file, the only callback called is postVisitDirectory. i.e., it doesn't visit the other files in the directory if you get an error visiting one file. This is what I mean. I'm sure there is probably some way to work around this, but by the time we got to this point we had already written more code than a traditional recursive delete routine, so we decided against using it.
  • Miquel
    Miquel almost 11 years
    Be VERY CAREFUL. This will dereference symlinks. If you are on e.g. linux, and have a folder foo with a link foo/link such that link->/, calling delete(new File(foo)) will delete as much of your filesystem as your user is allowed to!!
  • Bombe
    Bombe over 10 years
    Seeing that you usually don’t have problems nesting a couple of hundred method calls I think you’re likely to run into filesystem restrictions a lot earlier.
  • kevinarpe
    kevinarpe over 10 years
    Be careful with the list* methods for class java.io.File. From the Javadocs: "Returns null if this abstract pathname does not denote a directory, or if an I/O error occurs." So: if (currList.length > 0) { becomes if (null != currList && currList.length > 0) {
  • Erik Kaplun
    Erik Kaplun about 10 years
    Enhanced version with boolean return value and no duplication: pastebin.com/PqJyzQUx
  • Wytze
    Wytze over 8 years
    I use an ArrayDeque instead of a Stack which is slightly faster. (unsynchronized)
  • Dreamspace President
    Dreamspace President over 8 years
    Thanks for your 1st code, it was useful to me, but I had to change it, because it did not complete a simple deltree: I had to ignore the exception in "postVisitDirectory" and return CONTINUE regardless because the following simple tree could not fully be deleted: A directory inside which there was another directory inside of which was one file. All of which as simple/normal as it gets, on Windows.
  • Zero3
    Zero3 over 8 years
    This solution seems very elegant and contains no directory traversal logic at all!
  • Basil Musa
    Basil Musa over 8 years
    "To find a pearl dive deep into the ocean.". This is by far the neatest solution I found. Had to dive deep to find it. Brilliant!
  • Joehot200
    Joehot200 over 8 years
    @Miquel That doesn't make sense - Why would we want to be careful? Surely the point of the code provided is to remove an entire directory, which is what it appears to do. I do not understand what the danger is here.
  • Miquel
    Miquel over 8 years
    @Joehot200 you are right, calling delete on a directory symlink won't delete the directory, just the symlink itself. Deleting the directory would actually require following the symlink explicitly using ReadSymbolicLink. My bad! Well spotted
  • user7740901
    user7740901 about 8 years
    This helped me come up with a Scala version: Files.walk(path).iterator().toSeq.reverse.foreach(Files.dele‌​te)
  • Richard EB
    Richard EB about 8 years
  • Ajax
    Ajax over 7 years
    The apache commons version detects symlinks, and simply does not traverse the file's children.
  • VGR
    VGR over 7 years
    Is sorting really necessary? The walk method already guarantees a depth-first traversal.
  • namero999
    namero999 over 7 years
    The comparator could be recycled from Collections.reverseOrder() so your code would be for (Path p : Files.walk(directoryToDelete).sorted(reverseOrder()).toArray‌​(Path[]::new)) assuming it has been statically imported.
  • swe
    swe over 7 years
  • Mat
    Mat over 7 years
    "Code is" NOT "very simple" to simply delete a dir :-) But hey that's the best solution in pure java I reckon.
  • Jeff
    Jeff about 7 years
    @namero999 Do you mean Comparator.reverseOrder? Files.walk(dir) .sorted(Comparator.reverseOrder()) .toArray(Path[]::new))
  • namero999
    namero999 about 7 years
    @Jeff quite sure you are right, mostly went by memory there :)
  • Luke Hutchison
    Luke Hutchison about 7 years
    Following symlinks during a recursive delete is incredibly dangerous. I lost an irreplaceable photo and video collection because the first version of gnome-vfs accidentally set following symlinks as the default behavior during recursive delete. It is not the default behavior for rm, for good reason!
  • foo
    foo almost 7 years
    Why add another dependency when Java has a facility out of the box? See answer by RoK on this page, or stackoverflow.com/questions/35988192/…
  • Stephan
    Stephan over 6 years
    Please note that the walkFileTree overload used here "does not follow symbolic links". (Javadoc: docs.oracle.com/javase/7/docs/api/java/nio/file/…)
  • Xairoo
    Xairoo over 6 years
    You need to change the sort in the first one to .sorted(Comparator::reverseOrder) to delete all the directories. Otherwise the parent directory is ordered before the child, and thus won't delete since it isn't empty. Great answer for those using Java 8!
  • Robert Fleming
    Robert Fleming over 6 years
    Guava 21.0 added this as MoreFiles.deleteRecursively().
  • pvrforpranavvr
    pvrforpranavvr about 6 years
    We can use plain java code instead of using dependencies . Checkout my answer .
  • user1156544
    user1156544 about 6 years
    The correct way is .sorted(Comparator.reverseOrder()) The suggestion Comparator::reverseOrder does not work. See: stackoverflow.com/questions/43036611/…
  • Andres Luuk
    Andres Luuk over 5 years
    It all started from a java.nio.file.DirectoryNotEmptyException I got. I found out the case where visitFileFailed is used. If your directory structure has a junction type link in windows. This can cause you 2 issues: *) Files.walkFileTree follows the link into the junction and deletes everything there. *) If the junction target directory is already deleted then parsing the link by the Files.walkFileTree fails with NoSuchFileException which is catched in visitFileFailed.
  • Andres Luuk
    Andres Luuk over 5 years
    Doing most of the IO operations on a junkction path will fail. And the following booleans are all false: Files.exists(file), Files.isDirectory(file), Files.isSymbolicLink(file) But you can get some information out of the path with: BasicFileAttributes attrs = Files.readAttributes(file, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS); boolean isJunction = attrs.isDirectory() && attrs.isOther();
  • RoK
    RoK over 5 years
    Robin, pay attention at minus sign in "-o1.compareTo(o2)". It's the same as .sorted(Comparator.reverseOrder)
  • Tom Anderson
    Tom Anderson about 5 years
    You should probably call super.postVisitDirectory(dir, exc); in your postVisitDirectory method, to blow up if the walk could not list a directory.
  • Silwing
    Silwing over 4 years
    Is Files.walk sequential? Or does this answer need forEachOrdered instead of forEach to avoid trying to delete non-empty directories?
  • Beto Neto
    Beto Neto about 4 years
    Just use: .sorted((f1, f2) -> f2.compareTo(f1)), comparing f2 with f1 instead of f1 with f2.
  • Albert Hendriks
    Albert Hendriks about 4 years
    How does this perform compared to rm -rf ?
  • Joshua Pinter
    Joshua Pinter about 4 years
    @cricket_007 Which platforms?
  • OneCricketeer
    OneCricketeer about 4 years
    Windows? OpenWrt? BSD?
  • Joshua Pinter
    Joshua Pinter about 4 years
    @cricket_007 Definitely not Windows. This was tested and used on Android and macOS.
  • Trieu Nguyen
    Trieu Nguyen about 4 years
    Nice code, but there is one bug, when fixed, it works. The line f.delete() under deleteDirectory(f) will throws NoSuchFileException because the deleteDirectory(f) already delete that file. Every directory will become a path when passed in deleteDirectory(f) and being deleted by path.delete(). Therefore, we don't need f.delete() in if f.isDerectory section. So, just delete f.delete(); under deleteDirectory(f) and it will works.
  • rolve
    rolve over 3 years
    There's a problem with this answer: the stream returned by walk() should be closed, because it "contains references to one or more open directories" (Javadoc).
  • Antoniossss
    Antoniossss over 3 years
    NIce lifehack i guess.
  • Phi Quang Phuoc
    Phi Quang Phuoc over 2 years
    This code is found in the book "Core Java 2" of Cay S. Horstmann. Shouldn't the author be credited?
  • Tomasz Dzięcielewski
    Tomasz Dzięcielewski over 2 years
    I've written this code by myself, so it's coincidence that code which has to do the same looks the same.
  • Wecherowski
    Wecherowski over 2 years
    @Mat it's ridiculous how verbose Java APIs are once you start working with other languages, really.
  • Humpity
    Humpity about 2 years
    So simple. Why are there so many alternative answers ?