4

I have the following Java code which iterates through all the files in a directory and deletes them.

for(File file : tmpDir.listFiles())
{
    file.delete();
}

It does however not delete all files. Some, usually 20-30, out of a couple of thousand, are left behind when I do this. Is it possible to fix this, or have I stumbled upon some Java voodoo that is best left alone?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
user1049697
  • 2,479
  • 4
  • 29
  • 36
  • 2
    Maybe you don't have the permission to delete the file. Or it is locked, or it gets recreated or something else. Check the return value to know if the deletion was successful or not). Also consider that directories must be empty in order to be deleted. – Stefano Sanfilippo Nov 02 '13 at 17:22
  • any error? what files are not deleted? – WhileTrueSleep Nov 02 '13 at 17:22
  • 1
    Are you sure that you can delete all files manually ? May some are used by other programs. Try to catch the exception : _"Note that the Files class defines the delete method to throw an IOException when a file cannot be deleted. This is useful for error reporting and to diagnose why a file cannot be deleted."_ – Alexis C. Nov 02 '13 at 17:22
  • 1
    Make sure no file handlers are open for the files you are trying to delete. – Aakash Nov 02 '13 at 17:22
  • No, I have the rights and all that. It's a set of files that I generate, do some processing on, and delete again. But some files "stay behind" and are not deleted along with their brethren. – user1049697 Nov 02 '13 at 17:23
  • @ZouZou no exception is thrown in Java 1.6, maybe the OP is using the older JDK. – Stefano Sanfilippo Nov 02 '13 at 17:24
  • @StefanoSanfilippo The OP is using `File.delete()`, not `Files.delete(...)` from the NIO2 package. – Thorn G Nov 02 '13 at 17:27
  • @TomG well, yes, I guess I know... What is the relation between my comments and NIO2? – Stefano Sanfilippo Nov 02 '13 at 17:29

3 Answers3

11

It returns a boolean value, you should check that. From the JavaDoc:

Returns: true if and only if the file or directory is successfully deleted; false otherwise

You should check the value of the return and take action.

If it returns false it may well be that you do not have permission to delete the file.

In that case you can check whether the file is writeable by the application and if not attempt to make it writeable - again this returns a boolean. If successful you can try deleting again.

You could use a utility method:

private void deleteFile(final File f) throws IOException {
    if (f.delete()) {
        return;
    }
    if (!f.canWrite() && !f.setWritable(true)) {
        throw new IOException("No write permissions on file '" + f + "' and cannot set writeable.");
    }
    if (!f.delete()) {
        throw new IOException("Failed to delete file '" + f + "' even after setting writeable; file may be locked.");
    }
}

I would also take their advice in the JavaDoc:

Note that the Files class defines the delete method to throw an IOException when a file cannot be deleted. This is useful for error reporting and to diagnose why a file cannot be deleted.

Provided that you are using Java 7 that is. That method throws a number of exceptions that you can handle:

try {
    Files.delete(path);
} catch (NoSuchFileException x) {
    System.err.format("%s: no such" + " file or directory%n", path);
} catch (DirectoryNotEmptyException x) {
    System.err.format("%s not empty%n", path);
} catch (IOException x) {
    // File permission problems are caught here.
    System.err.println(x);
}

Example taken from the Oracle tutorial page.

Boris the Spider
  • 59,842
  • 6
  • 106
  • 166
  • 1
    I don't see why people upvote this. It does not answer the OP's question, it's better suited for a comment. – Stefano Sanfilippo Nov 02 '13 at 17:25
  • gets roughly half way there – clwhisk Nov 02 '13 at 17:27
  • 1
    I tried this, but it never returns false, so there are no "errors" when deleting the file. It seems like the files aren't being seen when the loop iterates and deletes them. – user1049697 Nov 02 '13 at 17:38
  • Have you tried printing out the names of the files iterated over into a logger and then searching for the problematic ones? Have you tried adding a breakpoint after the delete call to see if the file is recreated by something else? – Boris the Spider Nov 02 '13 at 17:47
  • @BoristheSpider I exited the program straight after the files are attemted deleted, and there are still some remaining. If I run the program over and over with the same input, different files are remaining for each iteration, so there is no "system" for what's being left behind. – user1049697 Nov 02 '13 at 19:15
  • @BoristheSpider I tried your code, and it gives the error "Failed to delete file even after setting writeable; file may be locked." So it turns out that the files are being hogged by another process even after it processed them and quit. – user1049697 Nov 04 '13 at 19:16
  • I would try using the `Files` method - the errors are much more informative. I think you are probably right in your presumptions about the file being locked however. – Boris the Spider Nov 04 '13 at 19:25
  • @BoristheSpider Yes, using the Files method I get told that it is locked by a process. But the weird thing is that all of the files in the folder are used by the same process, but only some of them are being locked. And the process should be dead after using them as well, so I don't even know how it can be zombie hogging them. – user1049697 Nov 05 '13 at 12:43
  • The most likely explanation is that you are not closing a resource somewhere/sometimes. An `InputStream` or `OutputStream` is not being closed so resources are not being released. If it's happening at random then it might be a race hazard (for the sake of your sanity I hope not)... – Boris the Spider Nov 05 '13 at 12:54
  • @BoristheSpider I found the error. Running ``System.gc();`` before deleting makes the files deletable. – user1049697 Nov 05 '13 at 12:59
3

Forcing the garbage collector to run using System.gc(); made all the files deletable.

user1049697
  • 2,479
  • 4
  • 29
  • 36
0

Make sure that you don't have any open stream like BufferedReader/Writer, FileReader/Writer etc. First close them, then you should be able to delete the file. One more point, E.g. if you open a BufferedReader via another reader like FileReader, you must close both of the readers seperately.

So instead of this:

BufferedReader reader = new BufferedReader(new FileReader(new File(filePath)););

do this:

BufferedReader bufferedReader = null;
FileReader fileReader = null;

try{
    fileReader = new FileReader(readFile);
    bufferedReader = new BufferedReader(fileReader);

}catch{...}

...

try {
    fileReader.close();
    bufferedReader .close();
    readFile.delete();
} catch (IOException e) {
    e.printStackTrace();
}
Melis
  • 75
  • 1
  • 7
  • This is wrong, see here: [Do I need to close() both FileReader and BufferedReader?](https://stackoverflow.com/questions/1388602/do-i-need-to-close-both-filereader-and-bufferedreader) – Max Vollmer Jun 25 '19 at 13:21