Java NIO中File.deleteOnExit()的替代方案?

Java NIO中File.deleteOnExit()的替代方案?,java,nio,Java,Nio,JavaIO具有,这是一种在JVM正常终止期间删除其调用的文件的方法。我发现这对于清理临时文件非常有用,尤其是在单元测试期间 但是,我在JavaNIO的类中没有看到同名的方法。我知道我可以执行path.toFile().deleteOnExit(),但我想知道是否有使用NIO的替代方案 还有别的选择吗?如果没有,为什么没有呢?在幕后,File.deleteOnExit()将通过Runtime.addShutdownHook()创建一个shutdownhook 然后,您可以对NIO执行相同的操作:

JavaIO具有,这是一种在JVM正常终止期间删除其调用的文件的方法。我发现这对于清理临时文件非常有用,尤其是在单元测试期间

但是,我在JavaNIO的类中没有看到同名的方法。我知道我可以执行
path.toFile().deleteOnExit()
,但我想知道是否有使用NIO的替代方案


还有别的选择吗?如果没有,为什么没有呢?

在幕后,
File.deleteOnExit()
将通过
Runtime.addShutdownHook()
创建一个
shutdownhook

然后,您可以对NIO执行相同的操作:

Runtime.getRuntime().addShutdownHook(new Thread() {
  public void run() {
    Path path = ...;

    Files.delete(path);
  }
});
简短回答 您不能在Java NIO中删除任意文件,但可以在打开新流时使用,它将在流关闭时立即删除文件,方法是调用
.close()
(包括通过try with resources语句)或JVM终止。例如:

Files.newOutputStream(Paths.get("Foo.tmp"), StandardOpenOption.DELETE_ON_CLOSE);
Files.newOutputStream(Paths.get("Foo.tmp"), StandardOpenOption.DELETE_ON_CLOSE);
长话短说 在深入研究之后,我发现JavaNIO确实有一种在退出时删除的方法,但它的处理方式与JavaI/O不同

首先,Javadoc for描述了三种删除文件的方法:

当用作工作文件[sic]时,可以打开生成的文件 使用该选项,以便在 调用适当的close方法。或者, 或者,该机制可用于删除该文件 自动地

最后一个选择,
File.deleteOnExit()
当然是一个Java I/O方法,我们正试图避免这种方法。shutdownhook是调用上述方法时在幕后发生的事情。但是
DELETE\u ON\u CLOSE
选项是纯Java NIO

JavaNIO没有删除任意文件,而是假设您只对删除实际打开的文件感兴趣。因此,创建一个新流的方法,例如,可以选择使用几个,您可以在其中输入。这样做是在流关闭后立即删除文件(通过调用
.close()
或JVM退出)

例如:

Files.newOutputStream(Paths.get("Foo.tmp"), StandardOpenOption.DELETE_ON_CLOSE);
Files.newOutputStream(Paths.get("Foo.tmp"), StandardOpenOption.DELETE_ON_CLOSE);
…将在流关闭时删除与流关联的文件,无论是从显式调用
.close()
、作为try with resources语句的一部分关闭流,还是JVM终止

更新:在某些操作系统(如Linux)上,
StandardOpenOption.DELETE\u On\u CLOSE
在创建输出流后立即删除。如果您只需要一个OutputStream,那可能还可以。有关更多信息,请参阅


因此,JavaNIO在JavaI/O上添加了新功能,您可以在关闭流时删除文件。如果这是JVM退出期间删除的一个足够好的替代方案,那么您可以在纯JavaNIO中完成。如果没有,您将不得不依靠Java I/O的
File.deleteOnExit()
或关闭挂钩来删除该文件。

我不建议使用shoe horn替换
File.deleteOnExit()
。正如文档中提到的,它既不是通用的,也不可能在琐碎的情况下正常工作

DELETE\u ON\u CLOSE
,顾名思义,就是立即清理不再需要的资源。在这一点上,的文档也很清楚,
DELETE\u on\u CLOSE
仅可用于打开文件时需要的“工作文件”

Files.createTempFile()
文档建议您直接编写自己的关闭挂钩,或者继续使用
File.deleteOnExit()
。尽管您希望使用NIO,但如果您只使用本地文件系统,那么使用
File.deleteOnExit()
本身并没有什么问题。如果您没有使用(或不确定您正在使用)本地文件系统,因此无法使用
File.deleteOnExit()
,那么编写您自己的关闭挂钩就足够简单了:

公共最终类DeletePathsAtShutdown{
私有静态LinkedHashSet文件=新LinkedHashSet();
静止的{
Runtime.getRuntime().addShutdownHook(
新线程(DeletePathsAtShutdown::shutdownHook));
}
私有静态void关闭钩子(){
LinkedHashSet本地;
同步的{
局部=路径;
路径=空;
}
ArrayList toBeDeleted=新的ArrayList(文件);
收款。反向(待删除);
对于(路径p:待删除){
试一试{
删除(p);
}捕获(IOException | RuntimeException e){
//什么也不做-尽最大努力
}
}
}
公共静态同步无效寄存器(路径p){
if(路径==null){
抛出新的IllegalStateException(“正在进行关机”);
}
添加(p);
}
}

当然,如果NIO在开箱即用的情况下包含一个类似的关闭钩子可能会更好,但它的缺失并不是使用错误工具的理由。您还可以向
DeletePathsAtShutdown
添加更多功能,例如
remove()
函数或对的支持。

NIO版本会做哪些不同或更好的事情?(除了从调用链中删除
.toFile()
)@Thunderforge DataInputStream.readLine()实际上在1998年被
@弃用,现在仍然存在。“完全生活在NIO中”的好处是什么?@PeterLawrey我知道Java倾向于不删除他们不喜欢的东西(这在我看来很奇怪,来自Python),但总有一天会删除的。至于“完全生活在NIO中”,如果代码完全在NIO中而不是两者都使用,那么代码将更容易掌握(特别是对于那些可能从NIO开始,以前从未使用过IO的年轻开发人员)。不管你是否同意这个理由,我还是想知道是否有其他选择。@Thunderforge我想说的是,在Java中,除非有令人信服的理由,否则他们会避免添加东西。每种方法