Java 无缘无故地锁定文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/586830/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 12:58:20  来源:igfitidea点击:

Java keeps lock on files for no apparent reason

javafilelocking

提问by Jonas K

Despite closing streams in finally clauses I seem to constantly run into cleaning up problems when using Java. File.delete() fails to delete files, Windows Explorer fails too. Running System.gc() helps sometimes but nothing short of terminating the VM helps consistently and that is not an option.

尽管在 finally 子句中关闭了流,但我在使用 Java 时似乎经常遇到清理问题。File.delete() 无法删除文件,Windows 资源管理器也无法删除。运行 System.gc() 有时会有所帮助,但只有终止 VM 才能始终如一地提供帮助,这不是一种选择。

Does anyone have any other ideas I could try? I use Java 1.6 on Windows XP.

有没有人有我可以尝试的其他想法?我在 Windows XP 上使用 Java 1.6。

UPDATE: FLAC code sample removed, the code worked if I isolated it.

更新:FLAC 代码示例已删除,如果我将其隔离,代码将起作用。

UPDATE: More info, this happens in Apache Tomcat, Commons FileUpload is used to upload the file and could be the culprit, also I use Runtime.exec() to execute LAME in a separate process to encode the file, but that seems unlikely to cause this since ProcessExplorer clearly indicates that java.exe has a RW lock on the file and LAME terminates fine.

更新:更多信息,这发生在 Apache Tomcat 中,Commons FileUpload 用于上传文件并且可能是罪魁祸首,我也使用 Runtime.exec() 在单独的进程中执行 LAME 来对文件进行编码,但这似乎不太可能这是因为 ProcessExplorer 清楚地表明 java.exe 在文件上有一个 RW 锁,并且 LAME 终止正常。

UPDATE: I am working with the assumption that there is a missing close() or a close() that does not get called somewhere in my code or external library. I just can't find it!

更新:我假设在我的代码或外部库中的某处没有被调用的 close() 或 close() 丢失。我就是找不到!

采纳答案by Bogdan

The code you posted looks good - it should not cause the issues you are describing. I understand you posted just a piece of the code you have - can you try extracting just this part to a separate program, run it and see if the issue still happens? My guess is that there is some other place in the code that does new FileInputStream(path);and does not close the stream properly. You might be just seeing the results here when you try to delete the file.

您发布的代码看起来不错 - 它不应该导致您所描述的问题。我知道您只发布了您拥有的一段代码 - 您可以尝试将这部分提取到一个单独的程序中,运行它并查看问题是否仍然存在?我的猜测是代码中还有其他一些地方可以new FileInputStream(path);正确关闭流,也不能正确关闭流。当您尝试删除文件时,您可能只是在此处看到结果。

回答by Eddie

I assume you're using jFlac. I downloaded jFlac 1.3 and tried your sample code on a flac freshly downloaded from the internet live music archive. For me, it worked. I even monitored it with ProcessExplorerand saw the file handles be opened and then released. Is your test code truly as simple as what you gave us, or is that a simplified version of your code? For me, once close() was called, the handle was released and the file was subsequently successfully deleted.

我假设您正在使用jFlac。我下载了 jFlac 1.3 并在刚从互联网现场音乐档案中下载的 flac 上尝试了您的示例代码。对我来说,它奏效了。我什至用ProcessExplorer监视它,看到文件句柄被打开然后释放。你的测试代码真的像你给我们的一样简单,还是你的代码的简化版本?对我来说,一旦 close() 被调用,句柄被释放,文件随后被成功删除。

Try changing your infinite loop to:

尝试将无限循环更改为:

File toDelete = new File(path);
if (!toDelete.delete()) {
  System.out.println("Could not delete " + path);
  System.out.println("Does it exist? " + toDelete.exists());
}

or if you want to keep looping, then put a 1 second sleep between attempts to delete the file. I tried this with JDK6 on WinXP Pro.

或者,如果您想继续循环播放,则在尝试删除文件之间放置 1 秒的睡眠时间。我在 WinXP Pro 上用 JDK6 试过这个。

Don't forget to put a try/catch around your close()and log errors if the close throws an exception.

close()如果关闭引发异常,请不要忘记在您的和日志错误周围放置一个 try/catch 。

回答by John Gardner

Isn't that an empty while loop?

这不是一个空的while循环吗?

you have:

你有:

try
{
...code
}
finally
{
}
while (something);

put some whitespace in there, and you actually have:

在那里放一些空格,你实际上有:

try
{
...code
}
finally
{
}


while (something)
   ;

your while loop isn't related to your try/finally. if your original try statement fails and the file isn't created, that while loop will never complete, because the try/finally will never execute a second time.

您的 while 循环与您的 try/finally 无关。如果您的原始 try 语句失败并且未创建文件,则 while 循环将永远不会完成,因为 try/finally 永远不会第二次执行。

did you intend to make that a do{ all your code } while (your while statement)? because that isn't what you have there.

您是否打算将其设为 do{ all your code } while (您的 while 语句)?因为那不是你所拥有的。

EDIT to clarify: my suggestion would be to change your while loop to have more info of why it can't delete:

编辑以澄清:我的建议是更改您的 while 循环以获取有关为什么无法删除的更多信息:

while (!file.delete())
{
    if (!file.exists())
        break; // the file doesn't even exist, of course delete will fail

    if (!file.canRead())
        break; // the file isn't readable, delete will fail

    if (!file.canWrite())
        break; // the file isn't writable, delete will fail
}

because if delete fails once, its just going to fail over and over and over, of course its going to hang there. you aren't changing the state of the file in the loop.

因为如果删除失败一次,它只会一遍又一遍地失败,当然它会挂在那里。您不会更改循环中文件的状态。

Now that you've added other info, like Tomcat, etc, is this a permissions issue? are you trying to write to a file that the user tomcat is running as (nobody?) vm can't create? or delete a file that the tomcat process can't delete?

现在您已经添加了其他信息,例如 Tomcat 等,这是权限问题吗?您是否正在尝试写入用户 tomcat 正在运行的文件(没有人?)vm 无法创建?或者删除一个tomcat进程无法删除的文件?

If process explorer/etc say java has a lock on the file, then something still has an open stream using it. someone might have not properly called close() on whatever streams are writing to the file?

如果进程资源管理器/等说 java 锁定了文件,那么某些东西仍然有一个使用它的打开流。有人可能没有在写入文件的任何流上正确调用 close() ?

回答by Dan Berindei

Your code sample should definitely work. In fact I ran your it on Java 1.6/Vista with jflac 1.3 and the source file is deleted, without any looping.

您的代码示例绝对可以工作。事实上,我在 Java 1.6/Vista 和 jflac 1.3 上运行你的它,源文件被删除,没有任何循环。

I'm guessing in your case another process is keeping the file open, perhaps a desktop search indexer or an antivirus. You can procexpto find which process is actually holding onto the file.

我猜在你的情况下,另一个进程正在保持文件打开,可能是桌面搜索索引器或防病毒软件。您可以procexp来查找实际持有该文件的进程。

回答by TofuBeer

Make sure you have your close calls in the finally block not in the try block. If there is no try/finally because the method throws the exception then add a try/finally and put the close in there.

确保您在 finally 块中而不是在 try 块中进行了关闭调用。如果没有 try/finally 因为该方法抛出异常,则添加一个 try/finally 并将关闭放在那里。

Look at the Windows Task Manager. For the Processes add the "Handles" column (under the View menu). Watch to see if the handles keep going up without ever dropping.

查看 Windows 任务管理器。对于进程添加“句柄”列(在视图菜单下)。观察手柄是否继续上升而不会掉落。

Use a profiler to see if you have Stream/Reader/Writer objects around that you do not think you should have.

使用分析器查看您周围是否有您认为不应该拥有的 Stream/Reader/Writer 对象。

EDIT:

编辑:

Thanks for posting the code... off to see it. One thing - your close methods are not both guaranteed to execute - the first close might throw and then the second won't run.

感谢您发布代码......去看看它。有一件事 - 您的关闭方法不能保证都执行 - 第一个关闭可能会抛出,然后第二个将不会运行。

EDIT 2:

编辑2:

final WavWriter wavWriter = new WavWriter(os); LACDecoder decoder = new FLACDecoder(is);

final WavWriter wavWriter = new WavWriter(os); LACDecoder 解码器 = 新的 FLACDecoder(is);

The above two lines will cause the strams to be kept in instance variables presumably. As a test see if you can set the stream references to null after the decoder.decode() call (make a decoder.cleanup() method perhaps). See if holding onto the closed streams is causing a problem.

上面两行大概会导致 strams 被保存在实例变量中。作为测试,看看您是否可以在decoder.decode() 调用之后将流引用设置为null(也许可以创建一个decoder.cleanup() 方法)。查看保持关闭的流是否会导致问题。

Also, do you do any wrapping of the streams passed into the above constructors? If so you might have to close the streams via the wrappers.

另外,您是否对传递给上述构造函数的流进行了任何包装?如果是这样,您可能必须通过包装器关闭流。

回答by fredarin

If you are out of clues and ideas: In cygwin, cd to your javaroot and run something like:

如果你没有线索和想法:在 cygwin 中,cd 到你的 javaroot 并运行类似的东西:

find . -name '*.java' -print0 | xargs -0 grep "new.*new.*putStream"

It might provide a few suspects...

它可能会提供一些嫌疑人......

回答by fredarin

Another thing to try since you're using Tomcat-- in your Context Descriptor (typically Tomcat/conf/Catalina/localhost/your-context.xml), you can set antiResourceLocking=true, which is designed to "avoid resource locking on Windows". The default for this (if you don't specify) is false. Worth a try.

由于您使用的是 Tomcat,因此要尝试的另一件事是在您的上下文描述符(通常是 Tomcat/conf/Catalina/localhost/your-context.xml)中进行设置 antiResourceLocking=true,它旨在“避免 Windows 上的资源锁定”。这个的默认值(如果你没有指定)是假的。值得一试。