Create temporary files and directories using Java NIO2

Temporary files and directories are very useful in many situations. One typical case is that you are writing some (usually large) file and you don’t want anybody to accidentally access and mess with it until is completely written and closed. Once it is ready, you just move it to the final location.

Another case is to use temporary file for processing large amounts of data in order to keep the usage of RAM in reasonable limit. This is what SQL databases do when executing queries accessing thousands or millions of rows.

Additionally, you may also use temporary files for storing intermediate results of some longer operations or storing data for undo operations or whatever you imagine.

Temporary files in Java 6 and before

If you are still using Java 6 or earlier, or you are interacting with older code, you may use the following static method of File class:

    public static File createTempFile(String prefix, String suffix) throws IOException;

This method creates empty temporary file in system-dependant default temporary-file directory (the one specified by java.io.tmpdir system property). The name of created file starts with given prefix and ends with given suffix. It also contains several randomly chosen characters in between. Prefix must be at least 3 characters long and if you pass null for second argument, default suffix of .tmp is used.

Below is a simple method creating such temporary file and writing 2 lines into it:

    private void createTempFileOldWay() throws IOException {
        File tempFile = File.createTempFile("tempfile-old", ".tmp");
        PrintWriter writer = null;
        try {
            writer = new PrintWriter(new FileWriter(tempFile));
            writer.println("Line1");
            writer.println("Line2");
        } finally {
            if (writer != null)
                writer.close();
        }
        
        System.out.printf("Wrote text to temporary file %s%n", tempFile.toString());
    }

Temporary directories in Java 6 and before

Here we have to face the truth that Java 6 and earlier does not provide any convenient method to create temporary directory. Therefore, you need to manually write one based on the value of java.io.tmpdir system property.

Here is one sample way to create and write a temporary file into temporary directory. Note that this time we use version of createTempFile() method which also accepts directory where temporary file will be placed.

    private void createTempFileWithDirOldWay() throws IOException {
        File tempDir = new File(System.getProperty("java.io.tmpdir", null), "tempdir-old");
        if (!tempDir.exists() && !tempDir.mkdir())
            throw new IIOException("Failed to create temporary directory " + tempDir);
        
        File tempFile = File.createTempFile("tempfile-old", ".tmp", tempDir);
        PrintWriter writer = null;
        try {
            writer = new PrintWriter(new FileWriter(tempFile));
            writer.println("Line1");
            writer.println("Line2");
        } finally {
            if (writer != null)
                writer.close();
        }
        System.out.printf("Wrote text to temporary file %s%n", tempFile.toString());
    }

Issues with temporary files and directories in Java 6 and before

Apart from lack of method for creating temporary directories, there is one additional problem. The temporary files created using methods above have very unrestricted file permissions so that (at least on my system) anybody can read it. If you are writing security-sensitive application (e.g. for encrypting data), it may be a serious issue.

New additions in Java 7

Java 7 introduced few new classes for managing files as part of NIO2. Two most interesting are Path and Files. The first one is very similar to File class but its name better describes its functionality. The second one is a simple utility class with only static methods which perform several very common operations on files.

Creating temporary files in Java 7

To create temporary file in system-dependant default temporary-directory you may use following method from Files class:

public static Path createTempFile(String prefix, String suffix, FileAttribute<?>... attrs) throws IOException;

This seems very similar to how it was done before but there are few differences. Prefix and suffix are optional and may be null. Also attributes are optional and you don’t have to pass any.

From the security point of view the most important thing is that the created temporary file have very restrictive permissions which should be acceptable for security-sensitive applications.

Here is the typical usage:

    private void createTempFile() throws IOException {
        Path tempFile = Files.createTempFile("tempfiles", ".tmp");
        List<String> lines = Arrays.asList("Line1", "Line2");
        Files.write(tempFile, lines, Charset.defaultCharset(), StandardOpenOption.WRITE);
        
        System.out.printf("Wrote text to temporary file %s%n", tempFile.toString());
    }

Creating temporary directories in Java 7

The good thing is that Java 7 introduced very convenient way to create temporary directory. It is completely enough to call createTempDirectory() method of Files class with specified prefix (or with null if you don’t care about prefix) and optional attributes. That’s all. Here is an example:

    private void createTempFileWithDir() throws IOException {
        Path tempDir = Files.createTempDirectory("tempfiles");
        
        Path tempFile = Files.createTempFile(tempDir, "tempfiles", ".tmp");
        List<String> lines = Arrays.asList("Line1", "Line2");
        Files.write(tempFile, lines, Charset.defaultCharset(), StandardOpenOption.WRITE);
        
        System.out.printf("Wrote text to temporary file %s%n", tempFile.toString());
    }

Deleting temporary files and directories

If you execute methods above, you will quickly notice that created temporary files are not automatically deleted and stay on the file-system long after the application finished. In reality the files may stay there for weeks or even months depending on your operating system.

The best solution is to call delete() method to delete the temporary file or directory when it is no longer needed but there three alternatives which may be useful in certain situations.

Deleting temporary file with shutdown hook

Java runtime allows to register several shutdown hooks which are the actions that will be executed once the application finishes normally. You can utilize this feature and register your own hook which will delete the file:

    private void createTempFileShutdownHook() throws IOException {
        final Path tempFile = Files.createTempFile("tempfiles-shutdown-hook", ".tmp");
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                try {
                    Files.delete(tempFile);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
                
        List<String> lines = Arrays.asList("Line1", "Line2");
        Files.write(tempFile, lines, Charset.defaultCharset(), StandardOpenOption.WRITE);
        
        System.out.printf("Wrote text to temporary file %s%n", tempFile.toString());
    }

Deleting temporary files using delete-on-exit

Class File from Java 6 provides method deleteOnExit() which schedules the file for deletion once the application finishes normally. The mechanism is very similar to shutdown hooks but is easier to use.

In case you have Path to the temporary file, you can easily convert it to File and call deleteOnExit() on it:

    private void createTempFileDeleteOnExit() throws IOException {
        Path tempFile = Files.createTempFile("tempfiles-delete-on-exit", ".tmp");
        tempFile.toFile().deleteOnExit();
        List<String> lines = Arrays.asList("Line1", "Line2");
        Files.write(tempFile, lines, Charset.defaultCharset(), StandardOpenOption.WRITE);

        System.out.printf("Wrote text to temporary file %s%n", tempFile.toString());
    }

Deleting temporary files on close

The last alternative is to open the file with DELETE_ON_CLOSE open option. This option ensures that once you close the file, it will be automatically deleted from file-system and won’t be accessible any more. Here is an example:

    private void createTempFileDeleteOnClose() throws IOException {
        Path tempFile = Files.createTempFile("tempfiles-delete-on-close", ".tmp");
        List<String> lines = Arrays.asList("Line1", "Line2");
        Files.write(tempFile, lines, Charset.defaultCharset(), StandardOpenOption.WRITE, StandardOpenOption.DELETE_ON_CLOSE);

        System.out.printf("Wrote text to temporary file %s%n", tempFile.toString());
    }

Issues with shutdown hooks and delete-on-exit

Shutdown hooks and delete-on-exit may seem like a good idea because there is no need to worry about when to delete the file. However, you should be very careful with them when building long-running applications like servers.

The first reason is that JVM has to somehow store and keep information about which files to delete which in turn increases memory usage. If you create a lot of temporary files, memory usage may become very high.

The second is that temporary files take some disc space and if they are not deleted regularly they may fill up the file-system and prevent creation of other temporary files in this and other applications. From user point of view this results in system and applications instability.

Issue with DELETE_ON_CLOSE

Open option DELETE_ON_CLOSE is also not perfect because if JVM fails to delete the file on close, it will schedule it for deletion on exit. This will in turn result in the same issues as described above.

Conclusion

Temporary files are very useful and common in many applications and Java 7 provides very convenient interface to manipulate them. The most difficult part is to properly monitor life-cycle of temporary files and delete them when they are no longer needed. It is especially important when the temporary files are large and the application runs for a long time.

Source code for examples is available as usual at GitHub.

Advertisements

About Robert Piasecki

Husband and father, Java software developer, Linux and open-source fan.
This entry was posted in Java and tagged , . Bookmark the permalink.

One Response to Create temporary files and directories using Java NIO2

  1. Klitos Kyriacou says:

    Sorry to reply to an old post, but I’ve just come across it. With regards to DELETE_ON_CLOSE, and specifically this example:

    Files.write(tempFile, lines, Charset.defaultCharset(), StandardOpenOption.WRITE, StandardOpenOption.DELETE_ON_CLOSE);

    isn’t this completely pointless, in the sense that the file is closed before Files.write() returns and therefore it is deleted, so no other code ever gets a chance to read it, so why write it in the first place?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s