Despite closing streams in finally clauses I seem to constantly run into cleaning up problems when using Java. File.delete() fails to delete files, Windows Explorer fails too. Running System.gc() helps sometimes but nothing short of terminating the VM helps consistently and that is not an option.

Does anyone have any other ideas I could try? I use Java 1.6 on Windows XP.

UPDATE: FLAC code sample removed, the code worked if I isolated it.

UPDATE:
More info, this happens in Apache Tomcat, Commons FileUpload is used to upload the file and could be the culprit, also I use Runtime.exec() to execute LAME in a separate process to encode the file, but that seems unlikely to cause this since ProcessExplorer clearly indicates that java.exe has a RW lock on the file and LAME terminates fine.

UPDATE: I am working with the assumption that there is a missing close() or a close() that does not get called somewhere in my code or external library. I just can't find it!

We need more information before we can help you. How are you opening the file? Are you absolutely positive that you are closing each file, and is it possible that a file is not getting closed? On delete, do you check the boolean return stat to know it is failing, and on which file?
–
EddieFeb 25 '09 at 17:03

Now that you've removed the sample code most of the answers don't make sense...
–
John GardnerFeb 26 '09 at 18:33

They do make sense. Somewhere in my code or my external libraries is there a missing close(), because the issue remains until a garbage collection is run. Then the FileOutputStream's finalize() is run and the file is closed and can be deleted.
–
Jonas KlemmingFeb 26 '09 at 19:57

7 Answers
7

The code you posted looks good - it should not cause the issues you are describing. I understand you posted just a piece of the code you have - can you try extracting just this part to a separate program, run it and see if the issue still happens?
My guess is that there is some other place in the code that does new FileInputStream(path); and does not close the stream properly. You might be just seeing the results here when you try to delete the file.

I have now used ProcessExplorer and it clearly indicates java.exe to have a handle with Share flag RW. Does that mean I should be looking for unclosed FileOutputStreams?
–
Jonas KlemmingFeb 26 '09 at 0:12

It is hard to guess what it is that you are doing with those files :-) But my guess is it should not be too hard to go through the code and find all the places where you potentially read/write that file and make sure the streams are closed.
–
BogdanFeb 26 '09 at 0:45

I assume you're using jFlac. I downloaded jFlac 1.3 and tried your sample code on a flac freshly downloaded from the internet live music archive. For me, it worked. I even monitored it with ProcessExplorer and saw the file handles be opened and then released. Is your test code truly as simple as what you gave us, or is that a simplified version of your code? For me, once close() was called, the handle was released and the file was subsequently successfully deleted.

The above two lines will cause the strams to be kept in instance variables presumably. As a test see if you can set the stream references to null after the decoder.decode() call (make a decoder.cleanup() method perhaps). See if holding onto the closed streams is causing a problem.

Also, do you do any wrapping of the streams passed into the above constructors? If so you might have to close the streams via the wrappers.

(In practice FileInputSteram.close will not actually throw, although that is no excuse.)
–
Tom Hawtin - tacklineFeb 25 '09 at 17:51

Setting these variables to null shouldn't make any difference.
–
EddieFeb 25 '09 at 18:41

it would make a difference if he is somehow keeping a hold of some of the other objects which in turn is causing the streams to be saved. THough once the stream is closed I cannot see why it would keep the file locked. I suspect he has some sort of resource leak.
–
TofuBeerFeb 25 '09 at 19:30

I have now used ProcessExplorer and it clearly indicates java.exe to have a handle with Share flag RW.
–
Jonas KlemmingFeb 26 '09 at 0:10

Since ProcessExplorer shows the file is opened for writing I would say it's not closed properly by commons-fileupload. Perhaps you can post the code that uses commons-fileupload?
–
Dan BerindeiFeb 26 '09 at 8:32

Yes, but I just can't find that missing finally block? FileUpload seems to do things right...
–
Jonas KlemmingFeb 26 '09 at 13:34

your while loop isn't related to your try/finally. if your original try statement fails and the file isn't created, that while loop will never complete, because the try/finally will never execute a second time.

did you intend to make that a do{ all your code } while (your while statement)?
because that isn't what you have there.

EDIT to clarify:
my suggestion would be to change your while loop to have more info of why it can't delete:

while (!file.delete())
{
if (!file.exists())
break; // the file doesn't even exist, of course delete will fail
if (!file.canRead())
break; // the file isn't readable, delete will fail
if (!file.canWrite())
break; // the file isn't writable, delete will fail
}

because if delete fails once, its just going to fail over and over and over, of course its going to hang there. you aren't changing the state of the file in the loop.

Now that you've added other info, like Tomcat, etc, is this a permissions issue? are you trying to write to a file that the user tomcat is running as (nobody?) vm can't create? or delete a file that the tomcat process can't delete?

If process explorer/etc say java has a lock on the file, then something still has an open stream using it. someone might have not properly called close() on whatever streams are writing to the file?

The while loop isn't empty, exactly. It says, while the file isn't successfully being deleted, try again to delete it.
–
EddieFeb 25 '09 at 18:22

1

Yes, your while isn't "empty", but your while is "dumb". its checking the exact same state over and over, and the inside of the while loop doesn't do anything to change it. how many times do you want the OS to tell you "you can't delete that file" without putting in some code to figure out why?
–
John GardnerFeb 26 '09 at 18:39

Another thing to try since you're using Tomcat-- in your Context Descriptor (typically Tomcat/conf/Catalina/localhost/your-context.xml), you can set
antiResourceLocking=true, which is designed to "avoid resource locking on Windows". The default for this (if you don't specify) is false. Worth a try.