File类的两个方法delete和deleteOnExit的作用都是删除文件,但两者是有差别的。
delete立即删除文件,通常删除文件调用此方法即可,如果文件是被当作临时存储被多个方法或对象引用,程序结束后需要关闭,此时只要在文件创建时使用deleteOnExit方法,就可以在程序结束时删除文件,而不需要在多个地方进行文件删除的动作。但是使用deleteOnExit删除文件时,如果失败是看不到失败原因的。
另外要注意的是,如果文件的流没有关闭的话,文件是无法删除的。
delete:删除File对象表示的文件或目录,如果表示的是目录,需要保证目录是空的,否则无法删除。若成功删除返回true,否则返回false。
deleteOnExit:当虚拟机终止时,删除File对象表示的文件或目录,如果表示的是目录,需要保证目录是空的,否则无法删除,无返回值。
可以看出两个方法的区别是,delete是立即执行删除,而deleteOnExit是程序退出虚拟机时才会删除。重点关注deleteOnExit方法,源码如下:
public void deleteOnExit() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkDelete(path);
}
if (isInvalid()) {
return;
}
DeleteOnExitHook.add(path);
}
从源码中可以看出deleteOnExit使用了DeleteOnExitHook类,这个类记录了在虚拟机关闭时需要删除的文件。源码如下:
package java.io;
import java.util.*;
import java.io.File;
/**
* This class holds a set of filenames to be deleted on VM exit through a shutdown hook.
* A set is used both to prevent double-insertion of the same file as well as offer
* quick removal.
*/
class DeleteOnExitHook {
private static LinkedHashSet<String> files = new LinkedHashSet<>();
static {
// DeleteOnExitHook must be the last shutdown hook to be invoked.
// Application shutdown hooks may add the first file to the
// delete on exit list and cause the DeleteOnExitHook to be
// registered during shutdown in progress. So set the
// registerShutdownInProgress parameter to true.
sun.misc.SharedSecrets.getJavaLangAccess()
.registerShutdownHook(2 /* Shutdown hook invocation order */,
true /* register even if shutdown in progress */,
new Runnable() {
public void run() {
runHooks();
}
}
);
}
private DeleteOnExitHook() {}
static synchronized void add(String file) {
if(files == null) {
// DeleteOnExitHook is running. Too late to add a file
throw new IllegalStateException("Shutdown in progress");
}
files.add(file);
}
static void runHooks() {
LinkedHashSet<String> theFiles;
synchronized (DeleteOnExitHook.class) {
theFiles = files;
files = null;
}
ArrayList<String> toBeDeleted = new ArrayList<>(theFiles);
// reverse the list to maintain previous jdk deletion order.
// Last in first deleted.
Collections.reverse(toBeDeleted);
for (String filename : toBeDeleted) {
(new File(filename)).delete();
}
}
}
DeleteOnExitHook使用了java的关闭钩子,通过LinkedHashSet保存要删除的文件路径,并且利用Set的特性来防止插入重复的路径,在删除时会反转顺序,按照与添加时相反的顺序进行删除。
delete立即删除文件,通常删除文件调用此方法即可,如果文件是被当作临时存储被多个方法或对象引用,程序结束后需要关闭,此时只要在文件创建时使用deleteOnExit方法,就可以在程序结束时删除文件,而不需要在多个地方进行文件删除的动作。但是使用deleteOnExit删除文件时,如果失败是看不到失败原因的。
另外要注意的是,如果文件的流没有关闭的话,文件是无法删除的。