Delete directories recursively in Java

JavaFile IoFilesystemsDelete Directory

Java Problem Overview


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?

Java Solutions


Solution 1 - Java

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 - Java

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 - Java

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 - Java

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

Files.walk(Paths.get("c:/dir_to_delete/"))
                .map(Path::toFile)
                .sorted((o1, o2) -> -o1.compareTo(o2))
                .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:

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

Solution 5 - Java

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

Solution 6 - Java

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

Solution 7 - Java

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

Solution 8 - Java

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

import org.springframework.util.FileSystemUtils;

boolean success = FileSystemUtils.deleteRecursively(new File("directory"));

Solution 9 - Java

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.

Solution 10 - Java

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) { /* ... */ }
      });

Solution 11 - Java

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

Solution 12 - Java

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

Solution 13 - Java

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

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

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:

Solution 14 - Java

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.

Solution 15 - Java

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

Solution 16 - Java

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

Solution 17 - Java

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

Solution 18 - Java

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!

Solution 19 - Java

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.

Solution 20 - Java

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

Solution 21 - Java

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

Solution 22 - Java

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.

Solution 23 - Java

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

Solution 24 - Java

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

Solution 25 - Java

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

Solution 26 - Java

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](http://docs.oracle.com/javase/8/docs/api/java/nio/file/Path.html?is-external=true "class or interface in java.nio.file") path, [RecursiveDeleteOption](https://guava.dev/releases/23.0/api/docs/com/google/common/io/RecursiveDeleteOption.html "enum in com.google.common.io")... options) throws [IOException](http://docs.oracle.com/javase/8/docs/api/java/io/IOException.html?is-external=true "class or interface in java.io") > > 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](http://docs.oracle.com/javase/8/docs/api/java/lang/Throwable.html?is-external=true#getSuppressed-- "class or interface in java.lang").

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionpaweloqueView Question on Stackoverflow
Solution 1 - JavaSteve KView Answer on Stackoverflow
Solution 2 - JavaericksonView Answer on Stackoverflow
Solution 3 - JavaTomasz DzięcielewskiView Answer on Stackoverflow
Solution 4 - JavaRoKView Answer on Stackoverflow
Solution 5 - JavaTrevor RobinsonView Answer on Stackoverflow
Solution 6 - JavaPaulitexView Answer on Stackoverflow
Solution 7 - JavatrianamView Answer on Stackoverflow
Solution 8 - JavaBen HutchisonView Answer on Stackoverflow
Solution 9 - JavaAndrew McKinlayView Answer on Stackoverflow
Solution 10 - Javauser3669782View Answer on Stackoverflow
Solution 11 - JavaAdamOutlerView Answer on Stackoverflow
Solution 12 - JavavladichoView Answer on Stackoverflow
Solution 13 - JavaPeterView Answer on Stackoverflow
Solution 14 - JavaJan-Terje SørensenView Answer on Stackoverflow
Solution 15 - JavaAgileProView Answer on Stackoverflow
Solution 16 - JavaWendelView Answer on Stackoverflow
Solution 17 - JavapvrforpranavvrView Answer on Stackoverflow
Solution 18 - JavaglueView Answer on Stackoverflow
Solution 19 - Javadimo414View Answer on Stackoverflow
Solution 20 - JavapaweloqueView Answer on Stackoverflow
Solution 21 - JavaAlexander Sidikov PfeifView Answer on Stackoverflow
Solution 22 - JavaJoshua PinterView Answer on Stackoverflow
Solution 23 - JavaYessyView Answer on Stackoverflow
Solution 24 - JavaBharat SinghView Answer on Stackoverflow
Solution 25 - JavadatahakiView Answer on Stackoverflow
Solution 26 - JavaSergey Vyacheslavovich BrunovView Answer on Stackoverflow