DELETE_ON_CLOSE的用处

时间:2015-12-18 10:32:18

标签: java nio

互联网上有很多例子显示如何使用StandardOpenOption.DELETE_ON_CLOSE,例如:

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

其他示例同样使用Files.newOutputStream(..., StandardOpenOption.DELETE_ON_CLOSE)

我怀疑所有这些例子都可能存在缺陷。写文件的目的是让你在某个时候回读它;否则,为什么还要写呢?但是,在你有机会阅读文件之前,不会删除文件吗?

如果你创建一个工作文件(用于处理太大而无法留在内存中的大量数据),那么你就不会使用RandomAccessFile代替读写访问权限?但是,就我所见,RandomAccessFile并没有为您提供指定DELETE_ON_CLOSE的选项。

那么有人可以告诉我DELETE_ON_CLOSE 实际有用吗?

3 个答案:

答案 0 :(得分:3)

首先,我同意你Files.write(myTempFile, ..., StandardOpenOption.DELETE_ON_CLOSE)在这个例子中使用DELETE_ON_CLOSE是没有意义的。在通过互联网进行(不那么激烈)搜索之后,我能找到的唯一一个显示上述用法的例子是你可能得到它的那个(http://softwarecave.org/2014/02/05/create-temporary-files-and-directories-using-java-nio2/)。

此选项不仅适用于Files.write(...)API制作非常明确:

  

此选项主要用于工作文件,它们仅由单个Java虚拟机实例使用。建议在打开其他实体同时打开的文件时,不建议使用此选项。

很抱歉,我不能给你一个有意义的简短例子,但是看到像操作系统使用的交换文件/分区这样的文件。如果当前JVM需要在光盘上临时存储数据,并且在关机后数据不再有用。作为实际例子,我会提到它类似于JEE应用程序服务器,它可能决定将某些实体序列化为光盘以释放内存。

编辑可能以下列(过度简化的代码)为例来说明原理。 (所以请:没有人应该开始讨论这个“数据管理”可能会有不同的做法,使用固定的临时文件名是坏的等等,...)

  • 在try-with-resource块中,出于某种原因需要外部化数据(原因不是讨论的主题)。
  • 您对此外部化数据具有随机读/写权限
  • 此外部化数据仅在try-with-resource块中使用
  • 使用StandardOpenOption.DELETE_ON_CLOSE选项,您不需要在自己使用后处理删除,JVM会关注它(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));
        }
    }
}

答案 1 :(得分:1)

DELETE_ON_CLOSE适用于工作临时文件。

如果您需要进行一些需要临时存储在文件上的操作,但不需要使用当前执行之外的文件 DELETE_ON_CLOSE为此提供了一个很好的解决方案。

一个例子是当你需要存储无法在内存中保留的信息时,例如因为它们太重了。 另一个例子是,当你需要临时存储信息时,你只需要在一瞬间就需要它们而你不想为此占用记忆。

想象一下,一个过程需要大量时间才能完成的情况。您将信息存储在文件中,然后才能使用它们(可能在几分钟或几小时后)。如果您不需要,这可以保证您不会将内存用于这些信息。

DELETE_ON_CLOSE尝试在显式关闭文件时调用方法close()或者在JVM关闭之前删除文件(如果之前没有手动关闭)。

答案 2 :(得分:1)

以下是两种可能的使用方法:

1。致电Files.newByteChannel

此方法返回适合读取和写入的SeekableByteChannel,其中可以修改当前位置。

对于需要将某些数据存储在内存中以进行读/写访问而在应用程序关闭后不需要保留的情况,这似乎非常有用。

2。写入文件,回读,删除:

使用任意文本文件的示例:

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));

此输出(如预期):

false
true
Hello, World!
false

这个例子显然是微不足道的,但我想有很多情况下这种方法可能派上用场。

但是,我仍然认为旧的File.deleteOnExit方法可能更好,因为您不需要在文件的任何读取操作期间保持输出流打开。