views:

1005

answers:

5

Supposing I have a File f that represents a directory, then f.delete() will only delete the directory if it is empty. I've found a couple of examples online that use File.listFiles() or File.list() to get all the files in the directory and then recursively traverses the directory structure and delete all the files. However, since it's possible to create infinitely recursive directory structures (in both Windows and Linux (with symbolic links)) presumably it's possible that programs written in this style might never terminate.

So, is there a better way to write such a program so that it doesn't fall into these pitfalls? Do I need to keep track of everywhere I've traversed and make sure I don't go around in circles or is there a nicer way?

Update: In response to some of the answers (thanks guys!) - I'd rather the code didn't follow symbolic links and stayed within the directory it was supposed to delete. Can I rely on the Commons-IO implementation to do that, even in the Windows case?

A: 

File.getCanonicalPath() will tell you the “real” name of the file, including resolved symlinks. When while scanning you come across a directory you alread know (because you stored them in a Map) bail out.

Bombe
I would have thought that would slow down a recursive deletion quite a bit. Couldn't you do a File.getPath().equals(File.getCanonicalPath())?
PintSizedCat
I’m not sure how many gazillions of recursive directories you want to process but a Map.put() and a Map.contains() per directory won’t slow you down. The code you suggested would only tell you that somewhere in your path are symbolic links. They might be above the directory you want to delete.
Bombe
Honestly: worry about getting the job done first. Only if it works perfectly and you can measure that it’s _too_ slow (whatever that means), only _then_ start worrying about performance. Premature optimization is so brainless that it hurts me. Physically.
Bombe
A: 

If you could know which files are symlinks, you could just skip over those.

There is unfortunately no "clean" way of detecting symlinks in Java. Check out this pure Java workaround or this one involving native code.

Morendil
+2  A: 

Try Apache Commons IO for a tested implementation.

However, I don't think it this handles the infinite-recursion problem.

Joshua Fox
look at the source: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/java/org/apache/commons/io/FileUtils.java?view=markupYou will see the deleteDirectory doesn't follow symbolic-links.
elou
+8  A: 

If you really want your recursive directory deletion to follow through symbolic links, then I don't think there is any platform independent way of doing so without keeping track of all the directories you have traversed.

However, in pretty much every case I can think of you would just want to delete the actual symbolic link pointing to the directory rather than recursively following through the symbolic link.

If this is the behaviour you want then you can use the FileUtils.deleteDirectory method in Apache Commons IO.

Il-Bhima
A: 

At least under MacOSX, deleting a symbolic link to a directory does not delete the directory itself, and can therefore be deleted even if the target directory is not empty.

I assume this holds for most POSIX operating systems. And as far as I know, links under windows are also just files, and can be deleted as such from a Java program.

Sebastian Ganslandt