Delete directories recursively in Java
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.)
paweloque
My current projects: https://orbit7.ch https://gobugfree.com Follow me on Twitter: @paweloque
Updated on July 08, 2022Comments
-
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 about 15 yearsI 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 about 15 yearsFile.delete() does not have that functionality.
-
brady about 15 yearsI 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 about 15 yearsGenerally, 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 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 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 over 12 yearsToo 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 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 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 about 11 yearsI 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 about 11 yearsI 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 about 11 yearsIf 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 almost 11 yearsBe VERY CAREFUL. This will dereference symlinks. If you are on e.g. linux, and have a folder
foo
with a linkfoo/link
such thatlink->/
, callingdelete(new File(foo))
will delete as much of your filesystem as your user is allowed to!! -
Bombe over 10 yearsSeeing 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 over 10 yearsBe careful with the
list*
methods for classjava.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) {
becomesif (null != currList && currList.length > 0) {
-
Erik Kaplun about 10 yearsEnhanced version with boolean return value and no duplication: pastebin.com/PqJyzQUx
-
Wytze over 8 yearsI use an ArrayDeque instead of a Stack which is slightly faster. (unsynchronized)
-
Dreamspace President over 8 yearsThanks 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 over 8 yearsThis solution seems very elegant and contains no directory traversal logic at all!
-
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 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 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 about 8 yearsThis helped me come up with a Scala version:
Files.walk(path).iterator().toSeq.reverse.foreach(Files.delete)
-
Richard EB about 8 years@Steve K, URL is now: svn.apache.org/viewvc/commons/proper/io/trunk/src/main/java/org/…
-
Ajax over 7 yearsThe apache commons version detects symlinks, and simply does not traverse the file's children.
-
VGR over 7 yearsIs sorting really necessary? The
walk
method already guarantees a depth-first traversal. -
namero999 over 7 yearsThe comparator could be recycled from
Collections.reverseOrder()
so your code would befor (Path p : Files.walk(directoryToDelete).sorted(reverseOrder()).toArray(Path[]::new))
assuming it has been statically imported. -
swe over 7 years@RichardEB url is now: github.com/apache/commons-io/blob/master/src/main/java/org/…
-
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 about 7 years@namero999 Do you mean
Comparator.reverseOrder
?Files.walk(dir) .sorted(Comparator.reverseOrder()) .toArray(Path[]::new))
-
namero999 about 7 years@Jeff quite sure you are right, mostly went by memory there :)
-
Luke Hutchison about 7 yearsFollowing 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 almost 7 yearsWhy 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 over 6 yearsPlease note that the walkFileTree overload used here "does not follow symbolic links". (Javadoc: docs.oracle.com/javase/7/docs/api/java/nio/file/…)
-
Xairoo over 6 yearsYou 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 over 6 yearsGuava 21.0 added this as MoreFiles.deleteRecursively().
-
pvrforpranavvr about 6 yearsWe can use plain java code instead of using dependencies . Checkout my answer .
-
user1156544 about 6 yearsThe correct way is
.sorted(Comparator.reverseOrder())
The suggestionComparator::reverseOrder
does not work. See: stackoverflow.com/questions/43036611/… -
Andres Luuk over 5 yearsIt 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 over 5 yearsDoing 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 over 5 yearsRobin, pay attention at minus sign in "-o1.compareTo(o2)". It's the same as .sorted(Comparator.reverseOrder)
-
Tom Anderson about 5 yearsYou should probably call
super.postVisitDirectory(dir, exc);
in yourpostVisitDirectory
method, to blow up if the walk could not list a directory. -
Silwing over 4 yearsIs Files.walk sequential? Or does this answer need forEachOrdered instead of forEach to avoid trying to delete non-empty directories?
-
Beto Neto about 4 yearsJust use:
.sorted((f1, f2) -> f2.compareTo(f1))
, comparingf2
withf1
instead off1
withf2
. -
Albert Hendriks about 4 yearsHow does this perform compared to rm -rf ?
-
Joshua Pinter about 4 years@cricket_007 Which platforms?
-
OneCricketeer about 4 yearsWindows? OpenWrt? BSD?
-
Joshua Pinter about 4 years@cricket_007 Definitely not Windows. This was tested and used on Android and macOS.
-
Trieu Nguyen about 4 yearsNice code, but there is one bug, when fixed, it works. The line
f.delete()
underdeleteDirectory(f)
will throws NoSuchFileException because thedeleteDirectory(f)
already delete that file. Every directory will become a path when passed indeleteDirectory(f)
and being deleted bypath.delete()
. Therefore, we don't needf.delete()
inif f.isDerectory
section. So, just deletef.delete();
under deleteDirectory(f) and it will works. -
rolve over 3 yearsThere'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 over 3 yearsNIce lifehack i guess.
-
Phi Quang Phuoc over 2 yearsThis code is found in the book "Core Java 2" of Cay S. Horstmann. Shouldn't the author be credited?
-
Tomasz Dzięcielewski over 2 yearsI've written this code by myself, so it's coincidence that code which has to do the same looks the same.
-
Wecherowski over 2 years@Mat it's ridiculous how verbose Java APIs are once you start working with other languages, really.
-
Humpity about 2 yearsSo simple. Why are there so many alternative answers ?