我有一个在Wildfly中运行的Web应用程序,部分应用程序使用临时文件:
File.createTempFile(...)
。
然后,该临时文件将用作读写java.io.RandomAccessFile流的目标文件。 RandomAccessFile的java.nio.channels.FileChannel是与之交互并最终被截断的内容(当我完成它时)。文件的某些部分通过FileChannel.map()
完成与文件的所有交互后,使用fileChannel.truncate(size)
将文件截断为适当的大小。这是总是抛出IOException的地方
at sun.nio.ch.FileDispatcherImpl.truncate0(Native Method)
IOException消息是通用的:
java.io.IOException: The requested operation cannot be performed on a file with a user-mapped section open
。
这是一个由同一个进程显式创建的临时文件,它在使用它的过程中一直保持打开状态,可能只需几秒钟。谷歌搜索表明可能AV软件有文件处理,或其他一些应用程序正在使用它,但我已尝试在各种VM和不同配置的常规窗口框上运行它,问题可靠地重现。我认为必须对文件工具进行一些真正的滥用,但我不知所措。
此外,在Linux机器上从未见过此异常,截断工作可靠。没有执行文件锁定,这是唯一正在使用的文件,正在缓冲并写入通道,但没有什么奇怪的事情发生。
为了记录,我创建了一些示例测试应用程序创建流,通道,临时文件,执行截断等,我无法在独立应用程序中重现该问题。不幸的是,我无法直接分享来源,因此我正在尽力描述发生了什么,希望有人遇到类似的事情并提供一些指导。
答案 0 :(得分:3)
我的问题似乎没有正确的答案/解决方案,但至少我发现了一些可以解决问题的细节,这要归功于@diginoise发布的评论链接。
我得到了异常,因为我试图截断一个存储器映射字节缓冲区仍处于“活动状态”的文件。显然,用户无法手动取消映射/释放该内存上的Windows句柄(请参阅oracle的bug数据库中的JDK bug)。
最后,我认为答案只是在我完成这些文件时不尝试截断/删除这些文件,而是在下次应用程序启动时跟踪它们并处理它们,这样他们就可以保证没有活动的内存映射。
顺便说一下,File.deleteOnExit()
在这些内存映射文件条件下也会失败。
在我实现下次启动时处理文件的更永久性修复之前,我已经通过反射选择了manually unmap内存。
这种缓解功能在不抛出错误的情况下运行,它允许截断,并且允许deleteOnExit,但这是一种短期不可持续的解决方法。根据FileChannel实现,使用反射来调用可能不存在的方法并不是一种好习惯。使用FilChannel的另一个实现,我可能已经破坏了永远不会被清理的临时文件。