file.delete()与file.deleteOnExit()
之前使用ftp下载文件的时候会用到File.createTempFil()创建临时文件存储数据,用完之后就用file.delete()与file.deleteOnExit()删除临时文件。在windows的开发环境进行测试时,临时文件会被创建在C:\Users\{当前电脑用户名}\AppData\Local\Temp该目录下。在现场环境,临时文件则会被创建在tomcat的temp文件夹下面。最近发现现场环境中temp下面居然堆积了大量的临时文件,然后查了一下代码发现是因为用了file.deleteOnExit()。
这里得介绍一下file.delete()与file.deleteOnExit()这两个删除文件方法:
file.delete() :删除文件,删除的是创建File对象时指定与之关联创建的那个文件.这是一个立刻执行的操作
file.deleteOnExit() : 在JVM进程退出的时候删除文件,通常用在临时文件的删除.这个不会立刻执行,会等到jvm进程退出的时候删除
这里看到一个”JVM进程退出”,这是什么意思呢?百度一下得到:
JVM的关闭意味着将停止系统中所有的任务
按照这里的介绍,当应用关闭的时候,应该就可以把临时文件删了。然而,现场环境还是存了一大堆的临时文件没有删除。
这时候查看一下源码:
File.java
1 public void deleteOnExit() { 2 SecurityManager security = System.getSecurityManager(); 3 if (security != null) { 4 security.checkDelete(path); 5 } 6 if (isInvalid()) { 7 return; 8 } 9 DeleteOnExitHook.add(path); 10 }
DeleteOnExitHook.java
1 package java.io; 2 import java.util.*; 3 import java.io.File; 4 5 /** 6 * This class holds a set of filenames to be deleted on VM exit through a shutdown hook. 7 * A set is used both to prevent double-insertion of the same file as well as offer 8 * quick removal. 9 */ 10 11 class DeleteOnExitHook { 12 private static LinkedHashSet<String> files = new LinkedHashSet<>(); 13 static { 14 // DeleteOnExitHook must be the last shutdown hook to be invoked. 15 // Application shutdown hooks may add the first file to the 16 // delete on exit list and cause the DeleteOnExitHook to be 17 // registered during shutdown in progress. So set the 18 // registerShutdownInProgress parameter to true. 19 sun.misc.SharedSecrets.getJavaLangAccess() 20 .registerShutdownHook(2 /* Shutdown hook invocation order */, 21 true /* register even if shutdown in progress */, 22 new Runnable() { 23 public void run() { 24 runHooks(); 25 } 26 } 27 ); 28 } 29 30 private DeleteOnExitHook() {} 31 32 static synchronized void add(String file) { 33 if(files == null) { 34 // DeleteOnExitHook is running. Too late to add a file 35 throw new IllegalStateException("Shutdown in progress"); 36 } 37 38 files.add(file); 39 } 40 41 static void runHooks() { 42 LinkedHashSet<String> theFiles; 43 44 synchronized (DeleteOnExitHook.class) { 45 theFiles = files; 46 files = null; 47 } 48 49 ArrayList<String> toBeDeleted = new ArrayList<>(theFiles); 50 51 // reverse the list to maintain previous jdk deletion order. 52 // Last in first deleted. 53 Collections.reverse(toBeDeleted); 54 for (String filename : toBeDeleted) { 55 (new File(filename)).delete(); 56 } 57 } 58 }
可以看出,使用deleteOnExit方法的话不会立刻删除,而是把文件地址先保存到一个链表中。ShutdownHook正常结束的话,就会把之前存的文件地址拿出来一个一个的删掉。如果异常结束的话,那么这些临时文件就删除不了了。
因此推断,现场环境的临时文件垃圾,是因为平时关闭应用是直接关闭窗口导致异常结束引起的。
值得一提的是,这样使用deleteOnExit方法的话会占用大量的内存,直至JVM终止,因此建议谨慎使用。
参考文章:
http://www.hackerav.com/?post=80616
https://blog.csdn.net/qq_44813090/article/details/104227356
来源:https://www.cnblogs.com/bestlmc/p/12370755.html