Sometimes, I come across the need for creating temporary files in my (Java) programs. For this purpose, I usually use Java's NIO with the Path API instead of the old File API. Here I discuss how a directory for temporary files further be scoped in time with Java's try-with-resources.
Introduction
NIO provides the function createTempFile in the class java.nio.file.Files. Since temporary files should go into temporary directories (to group them by purpose), this class also provides the method createTempDirectory. Equipped with all of this goodness, I would be ready to go. However, there are two things that I would like to be maximally convenient:
I want the temporary directory to be managed with Java 7's try-with-resources statement, i.e., to have a scope…
…at whose end it should be automatically deleted (together with whatever files and directories I created inside.
That would allow me to handle temporary files and folders in a way that ensures that nothing useless is left lying around without having to explicitly deleting files and folders when I am done. To implement both of the above features is fairly easy. However, there may be some minor issues with stuff I saw on the web, so I will just outline my approach here.
It should be noted that none of the stuff below has been tested sufficiently well. I cannot guarantee any fitness for use and will not assume any responsibility for anything.
Deleting Folders with Everything Inside
I can delete files and folders in Java with the method delete (again of class java.nio.file.Files). However, that will fail if I try to delete a folder which still has a file or another folder inside. Thus, I need to do that recursively. Since I want to mainly delete temporary folders and files, I want my code not to be fail-fast: If something goes wrong (e.g., a file cannot be deleted), it should continue and try to delete as many files and folders as possible and only at the very end throw an exception. This exception should contain as much information about what could not be deleted and why as possible. This makes my situation a bit different from other solutions, such as [1], which is the basis for my solution. I implement it as follows:
Besides not being fail-fast, this methods differs from my inspirational source [1] in another way: It does not employ any operating-system specific commands (such as rm or rd) but only relies on the Java API. The reasons for this are as follows:
The most important one may be that the Path API is not "platform-bound". It could be implemented for zip-file systems as well or for memory file systems. If you would have such a path and throw it into a platform-native command such as rd, all hell could break loose (because that path may map to anything, I think).
From an OS command, you may not get detailed error information.
Calling an OS command or running a process for each deletion may actually be slower (or faster, who knows, but I like deterministic behavior).
Apropos, deterministic: using OS-dependent commands may introduce slight differences in behavior on different OSes.
Also, you may only be able to implement OS-specific deletion for a small subset of OSes, such as Linux/Unix and Windows anyway. Plus I am not sure how reliable the detection of the OS is from within Java.
And you will actually somewhat depend on the versions of these OSes. Maybe the parameters of the commands change in an ever-so-subtle in the future or already differ amongst the many versions of Windows, for example – at least I wouldn't want to check or maintain that.
Finally, I think a Java program should stay within the boundaries of the virtual machine for as long as possible. I would only call outside processes if absolutely necessary. This is just a general design idea: Reduce outside dependencies, rely on the security settings, configuration, and implementation of the JVM.
Of course, there are also some good reasons for using OS-specific commands. For instance, they can probably better deal with the underlying file systems, better understand stuff such as hard and soft links (although these are maybe not so likely to be in a temporary directory), and they actually may be faster. All in all, it depends on the likings of the programmer which way to go.
Temporary Directory Managed with try-with-resources
Java 7's try-with-resources statement allows us to put an instance of AutoCloseable into a construct similar to a try…finally which ensures that its close method is called under all circumstances (unless the JVM is terminated ungracefully before). For I/O related stuff, we would implement its sub-interface Closeable.
We can use this mechanism and the above code to implement a temporary folder which, along with its contents, is deleted at the end of the try-with-resources scope as follows:
How to Use
This temporary folder can now be used as follows:
Running the above program (under Linux) should result in something like:
This means that a temporary folder was created. We then created a file inside that folder. Once the closing curly brace of the try-with-resources was reached, both have automatically been deleted.
P.S. A reason why I used NIO with the Path API is that it is not bound to real files on disk. One day, I may be able to use a file system in memory for some of the temporary files. In that case, my delete method would still work all the same.