系统文件异常被删除排查

问题现象

在系统开发过程中,有时会发现任务执行过程中,相关文件找不到导致执行异常。该文件是用户上传保存到系统的。由于该问题偶发出现,排查起来有一定困难。

问题分析和定位

因为这里是文件无法找到,所以排查的思路是从文件的全生命周期去排查:
1.文件的上传是否成功;
2.文件路劲是否正确;
3.文件在哪些地方被使用,其中哪些地方涉及到文件删除。

经过多轮排查分析,1、2两点都没有发现问题。在第3点上也没发现有对该文件的删除操作。之后写了一个对文件删除进行监控的工具,经过多次测试,没发现问题所在。
另外,通过数次对问题出现的场景进行复现,发现该问题是否和文件上传会有某些关联,即一旦上传文件后,可能导致该问题。按着这样的想法进行复现,也没有发现问题所在。
最后,通过在文件上传的代码中发现了问题所在:

{
 savePath.deleteOnExit();
 (MultipartFile) file.transferTo(savePath)
}

这里上传的逻辑是先删除目标位置相同的文件(如果存在),然后再上传。于是便有了以上代码。但是其中deleteOnExit方法引起了注意,从字面上的单词意思可以猜想:在退出的时候删除文件。随后,经过查询资料有如下认识:

File.deleteOnExit() 方法的执行原理是将文件或目录标记为在 JVM 终止时删除。具体来说,这是如何工作的:
1.标记文件
当调用 File.deleteOnExit() 方法时,JVM 会将该文件或目录添加到一个待删除列表中。这个列表由 JVM 内部维护。
2.注册钩子
调用 deleteOnExit() 方法时,如果没有注册相应的钩子(hook),JVM 会自动注册一个钩子方法。这个钩子方法会在 JVM 终止之前被调>用。
3.调用钩子方法
当 JVM 准备终止时,它会调用注册的钩子方法。钩子方法会遍历待删除列表,并对每个文件执行删除操作。
4.删除操作
钩子方法会尝试删除列表中的每一个文件。如果删除操作成功,则文件被删除;如果失败,则文件不会被删除,并且可能会记录一条错误>信息。

有了这些发现后,先上传一个文件,然后再结束JVM进程,果然复现文原来的问题。至此,系统文件异常被删除的问题原因已找到。

问题的解决

考虑到,如果文件已经存在,transferTo 方法会覆盖该文件。这意味着旧文件的内容将被新文件的内容取代。 如果文件不存在,transferTo 方法会创建一个新的文件。可以将原逻辑中的代码savePath.deleteOnExit()删除。

但是如果文件在 transferTo 过程中被其他进程锁定,可能会导致 IOException。这种情况下,你需要捕获异常并处理。更安全的做法是transferTo 之前显式地检查并删除旧文件。这里使用了java.nio.file包下的Files.deleteIfExists(savePath)替换原来的savePath.deleteOnExit()。

进一步思考

出现此类偶发问题的确不好排查。但无论什么问题,即便没有任何的发现,最后都需要归结到代码层面去找原因。另外出现此类问题也说明了开发人员对api的滥用和不熟悉。作为开发人员应该在平日多积累常用api,对不熟悉和了解的api需要查阅资料,思考后判定适合当前场景才能使用。
这里,还从一个侧面展示了开发人员对Exit (退出)和Exist (存在)这两个单词的混淆。

愿你我都能在各自的领域里不断成长,勇敢追求梦想,同时也保持对世界的好奇与善意!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值