Java无缘无故地锁定文件

时间:2009-02-25 16:51:52

标签: java file locking

尽管在finally子句中关闭了流,但在使用Java时我似乎总是遇到清理问题。 File.delete()无法删除文件,Windows资源管理器也失败。运行System.gc()有时会有所帮助,但是没有什么能够终止虚拟机一直有所帮助,而且这不是一种选择。

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

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

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

更新:我正在假设缺少close()或close()在我的代码或外部库中没有被调用。我只是找不到它!

7 个答案:

答案 0 :(得分:6)

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

答案 1 :(得分:3)

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

尝试将无限循环更改为:

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

或者如果你想保持循环,那么在尝试删除文件之间放一个1秒的睡眠。我在WinXP Pro上尝试使用JDK6。

如果关闭抛出异常,请不要忘记在close()周围放置一个try / catch并记录错误。

答案 2 :(得分:0)

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

查看Windows任务管理器。对于Processes,添加“Handles”列(在View菜单下)。观察手柄是否持续上升而不会掉落。

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

编辑:

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

编辑2:

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

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

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

答案 3 :(得分:0)

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

你有:

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

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

try
{
...code
}
finally
{
}


while (something)
   ;

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

你是否打算做(你的所有代码)而你(你的同时声明)? 因为那不是你所拥有的。

编辑澄清: 我的建议是改变你的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
}

因为如果删除失败一次,它只会进行故障转移,一遍又一遍,当然它会挂在那里。你没有改变循环中文件的状态。

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

如果process explorer / etc说java对文件有锁定,那么某些东西仍然有一个使用它的开放流。有人可能没有在写入文件的任何流上正确调用close()吗?

答案 4 :(得分:0)

您的代码示例应该绝对有用。事实上,我使用jflac 1.3在Java 1.6 / Vista上运行它,并且源文件被删除,没有任何循环。

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

答案 5 :(得分:0)

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

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

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

答案 6 :(得分:0)

在你的上下文描述符(通常是Tomcat / conf / Catalina / localhost / your-context.xml)中使用Tomcat后要尝试的另一件事,你可以设置 antiResourceLocking=true,旨在“避免Windows上的资源锁定”。此默认值(如果未指定)为false。值得一试。