436

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?

spongebob
  • 8,370
  • 15
  • 50
  • 83
paweloque
  • 18,466
  • 26
  • 80
  • 136

26 Answers26

501

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

FileUtils.deleteDirectory(new File("directory"));
Mogsdad
  • 44,709
  • 21
  • 151
  • 275
Steve K
  • 19,408
  • 6
  • 52
  • 50
  • 3
    This function probably wraps the code that erickson provided in his answer. – paweloque Apr 22 '09 at 22:42
  • 14
    It's a little more thorough. It handles things like symbolic links correctly on Linux/Unix. http://svn.apache.org/viewvc/commons/proper/io/trunk/src/java/org/apache/commons/io/FileUtils.java?view=markup – Steve K Apr 22 '09 at 22:48
  • 1
    @Steve K, URL is now: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/main/java/org/apache/commons/io/FileUtils.java?view=markup#l1569 – Richard EB Apr 12 '16 at 10:31
  • @RichardEB url is now: https://github.com/apache/commons-io/blob/master/src/main/java/org/apache/commons/io/FileUtils.java – swe Dec 06 '16 at 10:52
  • 2
    Why add another dependency when Java has a facility out of the box? See answer by RoK on this page, or https://stackoverflow.com/questions/35988192/java-nio-most-concise-recursive-directory-delete – foo Jul 03 '17 at 21:50
  • We can use plain java code instead of using dependencies . Checkout my answer . – pvrforpranavvr Mar 10 '18 at 17:28
  • Major drawback here is that it uses the old File type and not Path. – kap Jun 23 '23 at 21:52
196

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);
}
Community
  • 1
  • 1
erickson
  • 265,237
  • 58
  • 395
  • 493
  • 1
    I agree, what you write as an answer is a good solution. However I'd like the File.delete() method handle this case automatically. – paweloque Apr 22 '09 at 22:32
  • 11
    File.delete() does not have that functionality. – Ben S Apr 22 '09 at 22:34
  • 17
    @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. – Lawrence Dol Apr 23 '09 at 03:43
  • @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. – erickson Apr 23 '09 at 04:34
  • 46
    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!!* – Miquel Jun 07 '13 at 18:20
  • 4
    @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. – Joehot200 Feb 04 '16 at 22:20
  • 14
    @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](https://docs.oracle.com/javase/8/docs/api/java/nio/file/Files.html#readSymbolicLink-java.nio.file.Path-). My bad! Well spotted – Miquel Feb 07 '16 at 20:57
  • 2
    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! – Luke Hutchison Apr 11 '17 at 08:19
  • How does this perform compared to rm -rf ? – Albert Hendriks Feb 25 '20 at 09:47
  • So simple. Why are there so many alternative answers ? – Humpity Apr 03 '22 at 11:30
167

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;
   }
});
Tomasz Dzięcielewski
  • 3,829
  • 4
  • 33
  • 47
  • 2
    This solution seems very elegant and contains no directory traversal logic at all! – Zero3 Nov 28 '15 at 16:20
  • 1
    "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! – Basil Musa Dec 27 '15 at 10:43
  • 27
    "Code is" NOT "very simple" to simply delete a dir :-) But hey that's the best solution in pure java I reckon. – Mat Jan 11 '17 at 15:15
  • 1
    Please note that the walkFileTree overload used here "*does not follow symbolic links*". (Javadoc: http://docs.oracle.com/javase/7/docs/api/java/nio/file/Files.html#walkFileTree(java.nio.file.Path,%20java.nio.file.FileVisitor)) – Stephan Sep 16 '17 at 09:14
  • 5
    You should probably call `super.postVisitDirectory(dir, exc);` in your `postVisitDirectory` method, to blow up if the walk could not list a directory. – Tom Anderson Mar 21 '19 at 12:53
  • This code is found in the book "Core Java 2" of Cay S. Horstmann. Shouldn't the author be credited? – Phi Quang Phuoc Sep 20 '21 at 14:15
  • I've written this code by myself, so it's coincidence that code which has to do the same looks the same. – Tomasz Dzięcielewski Sep 22 '21 at 12:26
  • 1
    @Mat it's ridiculous how verbose Java APIs are once you start working with other languages, really. – Wecherowski Nov 16 '21 at 21:55
  • @Zero3: but it does?! The directory traversal logic is the core of this solution (walkFileTree). – foo Jan 14 '23 at 17:12
  • @foo that comment by me is over 6 years old by now, but I believe what I intended to say was that this solution does not implement the actual directory traversal logic (as in looping over files and handling subdirectories and such), unlike some of the other solutions posted. – Zero3 Feb 01 '23 at 09:47
88

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);
}
Aleksandr Dubinsky
  • 22,436
  • 15
  • 82
  • 99
RoK
  • 960
  • 1
  • 7
  • 6
  • 1
    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! – Robin Sep 20 '17 at 14:48
  • 3
    The correct way is `.sorted(Comparator.reverseOrder())` The suggestion `Comparator::reverseOrder` does **not** work. See: https://stackoverflow.com/questions/43036611/why-doesnt-sortedcomparatorreverseorder-work/43036643 – user1156544 May 08 '18 at 22:46
  • 4
    Robin, pay attention at minus sign in "-o1.compareTo(o2)". It's the same as .sorted(Comparator.reverseOrder) – RoK Dec 05 '18 at 18:18
  • Is Files.walk sequential? Or does this answer need forEachOrdered instead of forEach to avoid trying to delete non-empty directories? – Silwing Oct 30 '19 at 13:05
  • Just use: `.sorted((f1, f2) -> f2.compareTo(f1))`, comparing `f2` with `f1` instead of `f1` with `f2`. – Beto Neto Feb 17 '20 at 16:53
  • 4
    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). – rolve Sep 18 '20 at 08:34
  • NIce lifehack i guess. – Antoniossss Dec 15 '20 at 12:10
67

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.)

Trevor Robinson
  • 15,694
  • 5
  • 73
  • 72
  • 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.) – Hakanai May 03 '13 at 00:41
  • 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. – Trevor Robinson May 03 '13 at 17:07
  • 1
    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. – Hakanai May 06 '13 at 04:19
  • 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. – Dreamspace President Nov 18 '15 at 14:13
  • 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 Nov 02 '18 at 08:35
  • 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(); – Andres Luuk Nov 02 '18 at 08:35
35

Just saw my solution is more or less the same as erickson's, just packaged as a static method. Drop this somewhere, it's much lighter weight than installing all of Apache Commons for something that (as you can see) is quite 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();
    }
}
AndrewF
  • 1,827
  • 13
  • 25
Paulitex
  • 453
  • 6
  • 9
21

A solution with a stack and without recursive methods:

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();
    }
}
trianam
  • 211
  • 2
  • 2
  • 2
    +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. – Nathan Osman Mar 10 '13 at 00:08
  • 5
    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. – Bombe Sep 14 '13 at 12:37
  • 2
    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) {` – kevinarpe Nov 11 '13 at 11:01
  • 1
    I use an ArrayDeque instead of a Stack which is slightly faster. (unsynchronized) – Wytze Oct 30 '15 at 15:22
19

If you have Spring, you can use FileSystemUtils.deleteRecursively:

import org.springframework.util.FileSystemUtils;

boolean success = FileSystemUtils.deleteRecursively(new File("directory"));
Ben Hutchison
  • 4,823
  • 4
  • 26
  • 25
17

Guava had Files.deleteRecursively(File) supported until Guava 9.

From Guava 10:

Deprecated. This method suffers from poor symlink detection and race conditions. This functionality can be supported suitably only by shelling out to an operating system command such as rm -rf or del /s. This method is scheduled to be removed from Guava in Guava release 11.0.

Therefore, there is no such method in Guava 11.

spongebob
  • 8,370
  • 15
  • 50
  • 83
Andrew McKinlay
  • 2,431
  • 1
  • 24
  • 27
  • 6
    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. – Andrew McKinlay Dec 30 '11 at 22:50
  • 6
    @andrew The Apache Commons implementation should have similar problems to those that cause Guava to remove their implementation, see http://code.google.com/p/guava-libraries/issues/detail?id=365 – orip May 20 '12 at 13:16
  • The apache commons version detects symlinks, and simply does not traverse the file's children. – Ajax Aug 20 '16 at 00:20
  • 8
    Guava 21.0 added this as [MoreFiles.deleteRecursively()](https://google.github.io/guava/releases/21.0/api/docs/com/google/common/io/MoreFiles.html#deleteRecursively-java.nio.file.Path-com.google.common.io.RecursiveDeleteOption...-). – Robert Fleming Jan 05 '18 at 19:56
12
for(Path p : Files.walk(directoryToDelete).
        sorted((a, b) -> b.compareTo(a)). // reverse; files before dirs
        toArray(Path[]::new))
{
    Files.delete(p);
}

Or if you want to handle the IOException:

Files.walk(directoryToDelete).
    sorted((a, b) -> b.compareTo(a)). // reverse; files before dirs
    forEach(p -> {
        try { Files.delete(p); }
        catch(IOException e) { /* ... */ }
      });
user3669782
  • 797
  • 8
  • 6
  • 2
    This helped me come up with a Scala version: `Files.walk(path).iterator().toSeq.reverse.foreach(Files.delete)` – James Ward Feb 18 '16 at 23:31
  • Is sorting really necessary? The `walk` method already guarantees a depth-first traversal. – VGR Sep 01 '16 at 20:41
  • 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. – namero999 Oct 06 '16 at 13:41
  • @namero999 Do you mean `Comparator.reverseOrder`? `Files.walk(dir) .sorted(Comparator.reverseOrder()) .toArray(Path[]::new))` – Jeff Feb 23 '17 at 18:36
  • @Jeff quite sure you are right, mostly went by memory there :) – namero999 Feb 24 '17 at 19:20
11
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();
}
spongebob
  • 8,370
  • 15
  • 50
  • 83
AdamOutler
  • 870
  • 4
  • 13
  • 29
9
public static 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();
    }
}
Nathan
  • 8,093
  • 8
  • 50
  • 76
vladicho
  • 91
  • 1
  • 1
  • 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. – Trieu Nguyen May 18 '20 at 04:12
5

Two ways to fail with symlinks and the above code... and don't know the solution.

Way #1

Run this to create a test:

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

Here you see your test file and test directory:

$ ls testfile dirtodelete
testfile

dirtodelete:
linktodelete

Then run your commons-io deleteDirectory(). It crashes saying the file is not found. Not sure what the other examples do here. The Linux rm command would simply delete the link, and rm -r on the directory would also.

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

Way #2

Run this to create a test:

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

Here you see your test file and test directory:

$ ls dirtodelete testdir
dirtodelete:
dirlinktodelete

testdir:
testfile

Then run your commons-io deleteDirectory() or the example code people posted. It deletes not only the directory, but your testfile which is outside the directory being deleted. (It dereferences the directory implicitly, and deletes the contents). rm -r would delete the link only. You need to use something like this delete the dereferenced files: "find -L dirtodelete -type f -exec rm {} \;".

$ ls dirtodelete testdir
ls: cannot access dirtodelete: No such file or directory
testdir:
Peter
  • 51
  • 1
  • 1
4

You could use:

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

Deletes a file, never throwing an exception. If file is a directory, delete it and all sub-directories. The difference between File.delete() and this method are: A directory to be deleted does not have to be empty. No exceptions are thrown when a file or directory cannot be deleted.

Jan-Terje Sørensen
  • 14,468
  • 8
  • 37
  • 37
4

An optimal solution that handles exception consistently with the approach that an exception thrown from a method should always describe what that method was trying (and failed) to do:

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);
    }
}
AgilePro
  • 5,588
  • 4
  • 33
  • 56
3

In legacy projects, I need to create native Java code. I create this code similar to Paulitex code. See that:

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

And the unit test:

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

}
Wendel
  • 2,809
  • 29
  • 28
3

Below code recursively delete all contents in a given folder.

boolean deleteDirectory(File directoryToBeDeleted) {
    File[] allContents = directoryToBeDeleted.listFiles();
    if (allContents != null) {
        for (File file : allContents) {
            deleteDirectory(file);
        }
    }
    return directoryToBeDeleted.delete();
}
pvrforpranavvr
  • 2,708
  • 2
  • 24
  • 34
2

Guava provides a one-liner: MoreFiles.deleteRecursively().

Unlike many of the examples shared, it accounts for symbolic links and will not (by default) delete files outside the provided path.

dimo414
  • 47,227
  • 18
  • 148
  • 244
2

Here is a bare bones main method that accepts a command line argument, you may need to append your own error checking or mold it to how you see fit.

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

I hope that helps!

t0mm13b
  • 34,087
  • 8
  • 78
  • 110
glue
  • 95
  • 2
  • 6
1

Without Commons IO and < Java SE 7

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();
        }
Alexander Sidikov Pfeif
  • 2,418
  • 1
  • 20
  • 35
1

rm -rf was much more performant than FileUtils.deleteDirectory.

After extensive benchmarking, we found that using rm -rf was multiple times faster than using FileUtils.deleteDirectory.

Of course, if you have a small or simple directory, it won't matter but in our case we had multiple gigabytes and deeply nested sub directories where it would take over 10 minutes with FileUtils.deleteDirectory and only 1 minute with rm -rf.

Here's our rough Java implementation to do that:

// Delete directory given and all subdirectories and files (i.e. recursively).
//
static public boolean deleteDirectory( File file ) throws IOException, InterruptedException {
    if ( file.exists() ) {
        String deleteCommand = "rm -rf " + file.getAbsolutePath();
        Runtime runtime = Runtime.getRuntime();

        Process process = runtime.exec( deleteCommand );
        process.waitFor();

        return true;
    }

    return false;
}

Worth trying if you're dealing with large or complex directories.

Joshua Pinter
  • 45,245
  • 23
  • 243
  • 245
  • @cricket_007 Which platforms? – Joshua Pinter May 04 '20 at 21:50
  • Windows? OpenWrt? BSD? – OneCricketeer May 04 '20 at 22:08
  • 2
    @cricket_007 Definitely not Windows. This was tested and used on Android and macOS. – Joshua Pinter May 05 '20 at 15:40
  • The code will fail on a file with spaces in the name. I'd prefer to wait 10 mins :-) – David L. May 30 '23 at 15:16
  • @DavidL. Interesting. We never encountered that. Do you mean a directory with a space in the name or a space anywhere in the path to the directory? Or both? – Joshua Pinter May 30 '23 at 16:54
  • I'd say both. Following should be better: `runtime.exec(new String[] {"rm","-rf",file.getAbsolutePath()})` or `new ProcessBuilder("rm","-rf",file.getAbsolutePath()).start()`. I find your observation about the performance interesting, but it has also drawbacks: possibly introducing bugs, limiting the portability. – David L. May 31 '23 at 19:45
  • @DavidL. Agreed. Nothing comes for free and without compromise. I'll keep that in mind when using this. In our limited use case, we're never dealing with spaces in the path or directory name so it works but really good to know for other use cases. – Joshua Pinter Jun 01 '23 at 17:05
1

// Java 8 with lambda & stream, if param is directory

static boolean delRecursive(File dir) {
    return Arrays.stream(dir.listFiles()).allMatch((f) -> f.isDirectory() ? delRecursive(f) : f.delete()) && dir.delete();
}

// if param is file or directory

static boolean delRecursive(File fileOrDir) {
    return fileOrDir.isDirectory() ? Arrays.stream(fileOrDir.listFiles()).allMatch((f) -> delRecursive(f)) && fileOrDir.delete() : fileOrDir.delete();
}
Yessy
  • 1,172
  • 1
  • 8
  • 13
1

Guava 21.0 and later

There is the void deleteRecursively(Path path, RecursiveDeleteOption... options) throws IOException static method of the MoreFiles class available since Guava 21.0.

Please, see the Javadoc documentation:

public static void deleteRecursively(Path path, RecursiveDeleteOption... options) throws IOException

Deletes the file or directory at the given path recursively. Deletes symbolic links, not their targets (subject to the caveat below).

If an I/O exception occurs attempting to read, open or delete any file under the given directory, this method skips that file and continues. All such exceptions are collected and, after attempting to delete all files, an IOException is thrown containing those exceptions as suppressed exceptions.

1

Maybe a solution for this problem might be to reimplement the delete method of the File class using the code from erickson's answer:

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();
    }
  }
}
paweloque
  • 18,466
  • 26
  • 80
  • 136
  • 1
    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. – erickson Apr 22 '09 at 22:50
  • 4
    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. – Eddie Apr 22 '09 at 23:20
0

While files can easily be deleted using file.delete(), directories are required to be empty to be deleted. Use recursion to do this easily. For example:

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

i coded this routine that has 3 safety criteria for safer use.

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);
    }
}
datahaki
  • 600
  • 7
  • 23