我正在使用第三方JPEG / EXIF操作库(Mediautil),这让我感到头疼。我想更改图像的EXIF数据。为此,我需要将更新的版本写入临时文件,删除原始文件,然后将临时文件重命名为原始名称。
我的问题是File.delete()
调用失败并返回false
,大概是因为库仍然以某种方式打开它 - 但我已经完成了我在API中找到的所有内容以使其关闭所有溪流。更糟糕的是:问题似乎与时间有关,并且单元测试它发生的位置有时会失败,有时也不会 - 但代码不多线程。
奇怪的是,有一个库调用可以解决问题 - 但它也删除了我实际上并不想要的EXIF缩略图。看看代码,我绝对看不到它关闭任何可能保持开放的流。
任何想法如何解决这个问题?
修改
这是在Windows XP,Java 6.另一件事:我发现如果我在调用System.gc()
之前调用File.delete()
,它可以工作 - 大概是因为它会触发一些终结器。所以它肯定似乎是一个未封闭的流。
答案 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泄漏打开文件句柄的设计。
由于这是一个开源库,因此您使用的是源代码访问权限。因此,您应该能够确认这一点,并在必要时自行修复。要成为一名优秀的公民,请通过提交补丁将您的修复回馈给项目。