Friday, July 8, 2011

Automatic Deletion of Temporary Work Files in Java 7/Groovy

I have touched on several subjects in individual posts prior to this one that now come together in this single post. These subjects include use of File.deleteOnExit() in Groovy, creation of temporary files in Java, and use of the Java System property java.io.tmpdir to locate the temporary directory for a particular JVM instance. In this post, I look at different ways to ensure that files created "temporarily" as "work files" get deleted automatically.

There are many times in both application development and script development that I have need of temporary files that are not intended to be used outside of that script's or application's current execution. It is typically best to have the application or script using these temporary files both create them when needed and delete them when no longer needed. Files created for temporary tasks that are not intended to outlive the Java process that creates them are referred to in the Java documentation as "work files." Although these "work files" might be placed in any directory the application or script chooses as long as it ensures they get removed, a convenient location entirely intended for such a person is the temporary directory defined by the Java system property java.io.tmpdir.

For purposes of this post, I will be creating all files in the temporary directory defined by java.io.tmpdir and will use the new Java 7 class Files with its createTempFile methods to create those temporary files. That is all for setup. The real intent of this post is then to demonstrate different options for ensuring that these temporary files are truly temporary. In other words, this post covers multiple ways to establish automatic deletion of files intended to be temporary.

The Javadoc documentation for the methods Files.createTempFile talks about three ways to ensure that a temporarily created file is deleted as part of the "temporary file facility":
As with the File.createTempFile methods, this method is only part of a temporary-file facility. Where used as a work files, the resulting file may be opened using the DELETE_ON_CLOSE option so that the file is deleted when the appropriate close method is invoked. Alternatively, a shutdown-hook, or the File.deleteOnExit() mechanism may be used to delete the file automatically.
These are the three approaches to automatic cleanup of temporary files that I cover in this post and they are all demonstrated in the next code listing.

demoAutoTempFileDeletion.groovy
#!/usr/bin/env groovy
/**
 * demoAutoTempFileDeletion.groovy
 *
 * This script creates three temporary files and then demonstrates ways to
 * ensure that these temporary files are automatically removed by the time the
 * script's JVM ends. The three approaches for automatic file deletion
 * demonstrated in this script are use of StandardOpenOption.DELETE_ON_CLOSE,
 * File.deleteOnExit(), and Runtime.addShutdownHook(Thread).
 */

import java.nio.file.Files
import java.nio.file.Paths
import static java.nio.file.StandardOpenOption.*

@groovy.transform.Field def tempDir = System.getProperty('java.io.tmpdir')

println "\nTemporary directory is ${tempDir}"

/*
 * Demonstrate automatic file cleanup via StandardOpenOption.DELETE_ON_CLOSE
 */
def tempPath1 = Files.createTempFile("dustin1-", "-one")
def os = Files.newOutputStream(tempPath1, CREATE, APPEND, DELETE_ON_CLOSE)
os.write('This is file content.'.bytes)
listFiles(tempPath1)

/*
 * Demonstrate automatic file cleanup via File.deleteOnExit() 
 */
def tempPath2 = Files.createTempFile("dustin2-", "-two")
Files.write(tempPath2, 'This is also file content.'.bytes)
tempPath2.toFile().deleteOnExit()
listFiles(tempPath2)

/*
 * Demonstrate automatic file cleanup via shutdown-hook
 */
def tempPath3 = Files.createTempFile("dustin3-", "-three")
Files.write(tempPath3, 'This is even another file.'.bytes)
Runtime.getRuntime().addShutdownHook(new Thread()
{
   public void run()
   {
      Files.delete(tempPath3)
   }
});
listFiles(tempPath3)



/**
 * List files in temporary directory that meet naming convention for files
 * written by this script.
 *
 * @param progress String indicating progress.
 */
def void listFiles(progress)
{
   println "\n== After ${progress}\n"
   def currentDirectory = Paths.get(tempDir)
   currentDirectory.toFile().eachFile
   {
      def pathName = it.canonicalPath
      if (pathName.contains('dustin'))
      {
         println "\t${pathName}"
      }
   }
}

When the above script is executed, output similar to that in the next screen snapshot is generated.


The output shows that all three files are created by the script, but that by the time a directory listing is done on the temp defined by java.io.tmpdir, they have already been removed automatically. Each of the three temporarily created files was deleted automatically via a different mechanism.

The first file's automatic cleanup is achieved by providing of the Java 7 StandardOpenOption.DELETE_ON_CLOSE enum value to the Files.newOutputStream method. When the script exits, this file gets automatically deleted.

The second file's automatic cleanup is achieved by the more traditional File.deleteOnExit() method that I have previously discussed in the blog post Java's File.deleteOnExit() in Groovy.

The third file's automatic cleanup is achieved through the use of Runtime.addShutdownHook(Thread). In this case, the body of the thread is very simple, using a single statement taking advantage of Java 7's Files.delete(Path) method.


Conclusion

Scripts commonly need to create files for temporary use and Java now provides several easy approaches for ensuring automatic deletion of files meant to be temporary in nature and to be removed when the particular script or application is finished. In this post, I have demonstrated the three main approaches for automatic file deletion recommended by the Javadoc documentation for the Files.createTempFile method to be used in conjunction with the temporary file facility.

No comments: