java 如何诊断 File.delete() 返回 false / 查找未关闭的流?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2128537/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to diagnose File.delete() returning false / find unclosed streams?
提问by Michael Borgwardt
I'm working with a 3rd party JPEG/EXIF manipulation library (Mediautil) that is causing me some headaches. I want to change an image's EXIF data. To do this, I need to write the updated version to a temporary file, delete the original and then rename the temp file to the original name.
我正在使用第 3 方 JPEG/EXIF 操作库 ( Mediautil),这让我有些头疼。我想更改图像的 EXIF 数据。为此,我需要将更新版本写入临时文件,删除原始文件,然后将临时文件重命名为原始名称。
My problem is that the File.delete()call fails and returns false, presumably because the library still has it opened in some way - but I have done everything I can find in the API to make it close all streams. Even worse: the problem seems to be timing-dependant, and the Unit tests where it occurs sometimes fail and sometimes not - but the code is notmultithreaded.
我的问题是File.delete()调用失败并返回false,大概是因为库仍然以某种方式打开它 - 但我已经做了我可以在 API 中找到的所有内容以使其关闭所有流。更糟糕的是:问题似乎与时间有关,它发生的单元测试有时会失败,有时不会 - 但代码不是多线程的。
Bizarrely, there is one library call that removes the problem - but it also removes the EXIF thumbnail, which I don't actually want. And looking at the code, I absolutely can't see where it closes any streams that might otherwise stay open.
奇怪的是,有一个库调用可以解决这个问题——但它也删除了 EXIF 缩略图,我实际上并不想要。查看代码,我绝对看不出它在哪里关闭了任何可能保持打开状态的流。
Any ideas how to attack this problem?
任何想法如何解决这个问题?
Edit:This is on Windows XP, Java 6. And another thing: I have found out that if I call System.gc()before calling File.delete(), it works - presumably because that triggers some finalizer. So it definitely seems to be an unclosed stream.
编辑:这是在 Windows XP、Java 6 上。还有另一件事:我发现如果我在调用System.gc()之前调用File.delete()它,它可以工作 - 大概是因为这会触发一些终结器。所以它绝对似乎是一个未关闭的流。
采纳答案by skaffman
I would go for some help with the debugger here. A quick dig through the java.iostuff shows that the only likely finalize()candidate is in FileOutputStream. So slap a breakpoint in there, run your program, and try and get System.gc()to trigger FileOutputStream.finalize()to release your stream. That should give you an answer as to whether or not that's your problem.
我会在这里寻求调试器的帮助。快速浏览这些java.io内容表明唯一可能的finalize()候选人在FileOutputStream. 所以在那里打一个断点,运行你的程序,然后尝试System.gc()触发FileOutputStream.finalize()以释放你的流。这应该会给你一个关于这是否是你的问题的答案。
Once you can reproduce that, then you need to start matching instantiation of FileOutputStreaminstances with their finalization. A good debugger will give you internal JVM object identifiers for each object, so if you can track the OIDs as they get created, and track them as they get finalized, then hopefully you'll be able to associate the key call to finalizewith a specific call new new FileOutputStream.
一旦你可以重现它,那么你需要开始匹配实例的FileOutputStream实例化和它们的最终化。一个好的调试器将为您提供每个对象的内部 JVM 对象标识符,因此如果您可以在创建 OID 时跟踪它们,并在它们最终确定时跟踪它们,那么希望您能够将键调用finalize与特定的调用新的new FileOutputStream。
Might be a long slog, though, depending how complex your application is.
不过,这可能是一个漫长的过程,这取决于您的应用程序的复杂程度。
回答by nkatsar
If you are using a FileOutputStream, closing it explicitly allows for deletion of the file.
如果您使用的是 FileOutputStream,则明确关闭它允许删除文件。
e.g. instead of:
例如,而不是:
File myFile = new File("test.txt");
myCustomStreamProcess(new FileOutputStream(myFile));
boolean test = myFile.delete(); //May return false
you should do:
你应该做:
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
回答by Adrian Pronk
Why don't you rename the file before you get the library to open it? Then maybe use Java's File.deleteOnExit() to delete the renamed file. For example:
为什么不在让库打开文件之前重命名文件?然后可能使用 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();
回答by Stephen C
And looking at the code, I absolutely can't see where it closes any streams that might otherwise stay open.
查看代码,我绝对看不出它在哪里关闭了任何可能保持打开状态的流。
I think you could have identified the real problem; i.e. that the API you are using leaks open file handles by design.
我认为您可以确定真正的问题;即您正在使用的 API 泄漏打开文件句柄设计。
Since this is an open source library you are using you have source code access. Therefore, you should be able to confirm this, and if necessary fix it for yourself. And to be a good citizen, contribute your fix back to the project by submitting a patch.
由于这是一个开源库,您正在使用您可以访问源代码。因此,您应该能够确认这一点,并在必要时自行修复。为了成为一个好公民,请通过提交补丁将您的修复回馈给项目。

