Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Usefulness of DELETE_ON_CLOSE

Tags:

java

nio

There are many examples on the internet showing how to use StandardOpenOption.DELETE_ON_CLOSE, such as this:

Files.write(myTempFile, ..., StandardOpenOption.DELETE_ON_CLOSE);

Other examples similarly use Files.newOutputStream(..., StandardOpenOption.DELETE_ON_CLOSE).

I suspect all of these examples are probably flawed. The purpose of writing a file is that you're going to read it back at some point; otherwise, why bother writing it? But wouldn't DELETE_ON_CLOSE cause the file to be deleted before you have a chance to read it?

If you create a work file (to work with large amounts of data that are too large to keep in memory) then wouldn't you use RandomAccessFile instead, which allows both read and write access? However, RandomAccessFile doesn't give you the option to specify DELETE_ON_CLOSE, as far as I can see.

So can someone show me how DELETE_ON_CLOSE is actually useful?

like image 730
Klitos Kyriacou Avatar asked Dec 18 '15 10:12

Klitos Kyriacou


People also ask

What is StandardOpenOption?

The StandardOpenOption enum type defines the standard options and implements the OpenOption interface. Here's the list of supported options we can use with the StandardOpenOptions enum: WRITE: opens the file for write access. APPEND: appends some data to the file. TRUNCATE_EXISTING: truncates the file.

What is file deleteOnExit?

deleteOnExit() method deletes the file or directory defined by the abstract path name when the virtual machine terminates. Files or directories are deleted in the reverse order as they are registered.


3 Answers

First of all I agree with you Files.write(myTempFile, ..., StandardOpenOption.DELETE_ON_CLOSE) in this example the use of DELETE_ON_CLOSE is meaningless. After a (not so intense) search through the internet the only example I could find which shows the usage as mentioned was the one from which you might got it (http://softwarecave.org/2014/02/05/create-temporary-files-and-directories-using-java-nio2/).

This option is not intended to be used for Files.write(...) only. The API make is quite clear:

This option is primarily intended for use with work files that are used solely by a single instance of the Java virtual machine. This option is not recommended for use when opening files that are open concurrently by other entities.

Sorry I can't give you a meaningful short example, but see such file like a swap file/partition used by an operating system. In cases where the current JVM have the need to temporarily store data on the disc and after the shutdown the data are of no use anymore. As practical example I would mention it is similar to an JEE application server which might decide to serialize some entities to disc to freeup memory.

edit Maybe the following (oversimplified code) can be taken as example to demonstrate the principle. (so please: nobody should start a discussion about that this "data management" could be done differently, using fixed temporary filename is bad and so on, ...)

  • in the try-with-resource block you need for some reason to externalize data (the reasons are not subject of the discussion)
  • you have random read/write access to this externalized data
  • this externalized data only is of use only inside the try-with-resource block
  • with the use of the StandardOpenOption.DELETE_ON_CLOSE option you don't need to handle the deletion after the use yourself, the JVM will take care about it (the limitations and edge cases are described in the API)

.

static final int RECORD_LENGTH = 20;
static final String RECORD_FORMAT = "%-" + RECORD_LENGTH + "s";

// add exception handling, left out only for the example
public static void main(String[] args) throws Exception {
    EnumSet<StandardOpenOption> options = EnumSet.of(
            StandardOpenOption.CREATE,
            StandardOpenOption.WRITE,
            StandardOpenOption.READ,
            StandardOpenOption.DELETE_ON_CLOSE
    );

    Path file = Paths.get("/tmp/enternal_data.tmp");
    try (SeekableByteChannel sbc = Files.newByteChannel(file, options)) {

        // during your business processing the below two cases might happen
        // several times in random order

        // example of huge datastructure to externalize
        String[] sampleData = {"some", "huge", "datastructure"};
        for (int i = 0; i < sampleData.length; i++) {
            byte[] buffer = String.format(RECORD_FORMAT, sampleData[i])
                    .getBytes();
            ByteBuffer byteBuffer = ByteBuffer.wrap(buffer);
            sbc.position(i * RECORD_LENGTH);
            sbc.write(byteBuffer);
        }

        // example of processing which need the externalized data
        Random random = new Random();
        byte[] buffer = new byte[RECORD_LENGTH];
        ByteBuffer byteBuffer = ByteBuffer.wrap(buffer);
        for (int i = 0; i < 10; i++) {
            sbc.position(RECORD_LENGTH * random.nextInt(sampleData.length));
            sbc.read(byteBuffer);
            byteBuffer.flip();
            System.out.printf("loop: %d  %s%n", i, new String(buffer));
        }
    }
}
like image 148
SubOptimal Avatar answered Nov 07 '22 02:11

SubOptimal


Here are two possible ways it can be used:

1. When calling Files.newByteChannel

This method returns a SeekableByteChannel suitable for both reading and writing, in which the current position can be modified.

Seems quite useful for situations where some data needs to be stored out of memory for read/write access and doesn't need to be persisted after the application closes.

2. Write to a file, read back, delete:

An example using an arbitrary text file:

Path p = Paths.get("C:\\test", "foo.txt");
System.out.println(Files.exists(p));
try {
    Files.createFile(p);
    System.out.println(Files.exists(p));
    try (BufferedWriter out = Files.newBufferedWriter(p, Charset.defaultCharset(), StandardOpenOption.DELETE_ON_CLOSE)) {
        out.append("Hello, World!");
        out.flush();
        try (BufferedReader in = Files.newBufferedReader(p, Charset.defaultCharset())) {
            String line;
            while ((line = in.readLine()) != null) {
                System.out.println(line);
            }
        }
    }
} catch (IOException ex) {
    ex.printStackTrace();
}
System.out.println(Files.exists(p));

This outputs (as expected):

false
true
Hello, World!
false

This example is obviously trivial, but I imagine there are plenty of situations where such an approach may come in handy.

However, I still believe the old File.deleteOnExit method may be preferable as you won't need to keep the output stream open for the duration of any read operations on the file, too.

like image 25
daiscog Avatar answered Nov 07 '22 00:11

daiscog


The DELETE_ON_CLOSE is intended for working temp files.

If you need to make some operation that needs too be temporaly stored on a file but you don't need to use the file outside of the current execution a DELETE_ON_CLOSE in a good solution for that.

An example is when you need to store informations that can't be mantained in memory for example because they are too heavy. Another example is when you need to store temporarely the informations and you need them only in a second moment and you don't like to occupy memory for that.

Imagine also a situation in which a process needs a lot of time to be completed. You store informations on a file and only later you use them (perhaps many minutes or hours after). This guarantees you that the memory is not used for those informations if you don't need them.

The DELETE_ON_CLOSE try to delete the file when you explicitly close it calling the method close() or when the JVM is shutting down if not manually closed before.

like image 2
Davide Lorenzo MARINO Avatar answered Nov 07 '22 02:11

Davide Lorenzo MARINO