如何诊断File.delete()返回false / find unclosed streams?

时间:2010-01-24 19:56:46

标签: java io

我正在使用第三方JPEG / EXIF操作库(Mediautil),这让我感到头疼。我想更改图像的EXIF数据。为此,我需要将更新的版本写入临时文件,删除原始文件,然后将临时文件重命名为原始名称。

我的问题是File.delete()调用失败并返回false,大概是因为库仍然以某种方式打开它 - 但我已经完成了我在API中找到的所有内容以使其关闭所有溪流。更糟糕的是:问题似乎与时间有关,并且单元测试它发生的位置有时会失败,有时也不会 - 但代码多线程。

奇怪的是,有一个库调用可以解决问题 - 但它也删除了我实际上并不想要的EXIF缩略图。看看代码,我绝对看不到它关闭任何可能保持开放的流。

任何想法如何解决这个问题?

修改 这是在Windows XP,Java 6.另一件事:我发现如果我在调用System.gc()之前调用File.delete(),它可以工作 - 大概是因为它会触发一些终结器。所以它肯定似乎是一个未封闭的流。

4 个答案:

答案 0 :(得分:5)

我会在这里寻求调试器的帮助。通过java.io内容快速浏览,可以看出finalize()候选人FileOutputStream只有System.gc()。所以在那里打一个断点,运行你的程序,并尝试让FileOutputStream.finalize()触发FileOutputStream来释放你的流。这应该可以帮助你回答这是否是你的问题。

一旦你可以重现它,那么你需要开始匹配finalize实例的实例化和它们的最终化。一个好的调试器将为每个对象提供内部JVM对象标识符,因此如果您可以在创建OID时跟踪它们,并在它们最终确定时跟踪它们,那么希望您能够将密钥调用关联到{{1使用特定的调用新new FileOutputStream

但是,根据您的应用程序的复杂程度,可能需要很长时间。

答案 1 :(得分:1)

如果您使用的是FileOutputStream,则明确关闭它会允许删除该文件。

e.g。而不是:

File myFile = new File("test.txt");
myCustomStreamProcess(new FileOutputStream(myFile));
boolean test = myFile.delete(); //May return false

你应该这样做:

File myFile = new File("test.txt");
FileOutputStream fos = new FileOutputStream(myFile);
myCustomStreamProcess(fos);
fos.close(); //Allow the document to be deleted afterwards
boolean test = myFile.delete(); //Should always return true

答案 2 :(得分:0)

为什么不在文件库打开之前重命名文件?然后可以使用Java的File.deleteOnExit()来删除重命名的文件。例如:

 File jpeg = new File("image.jpg");
 File temp = new File(jpeg + ".temp.jpg");
 jpg.renameTo(temp);
 SomeObj result = exifLibrary(temp); // or exifLibrary(new FileInputStream(temp);
 OutputStream jpegStream = new FileOutputStream(jpeg);
 output.write(result.bytes();
 output.close();
 temp.deleteOnExit();
 temp.delete();

答案 3 :(得分:0)

  

在查看代码时,我绝对看不到它关闭任何可能保持打开状态的流。

我认为你可以确定真正的问题;即你正在使用的API泄漏打开文件句柄的设计。

由于这是一个开源库,因此您使用的是源代码访问权限。因此,您应该能够确认这一点,并在必要时自行修复。要成为一名优秀的公民,请通过提交补丁将您的修复回馈给项目。