如何查找renameTo()失败的原因?

32

我正在使用WinXP。我使用Java生成文件列表。该文件首先将被创建为abc.txt.temp,完成生成后,将被重命名为abc.txt。

然而,在生成文件时,一些文件无法重命名。这种情况发生得很随机。

有没有办法找出它失败的原因?

int maxRetries = 60;
logger.debug("retry");
while (maxRetries-- > 0)
{
    if (isSuccess = file.renameTo(file2))
    {
        break;
    }
    try
    {
        logger.debug("retry " + maxRetries);
        Thread.sleep(1000);
    }
    catch (InterruptedException e)
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }   
}

//file.renameTo(file2);
Thread.currentThread().getThreadGroup().getParent().list();

结果如下:

[DEBUG][2009-08-25 08:57:52,386] - retry 1
[DEBUG][2009-08-25 08:57:53,386] - retry 0
java.lang.ThreadGroup[name=system,maxpri=10]
    Thread[Reference Handler,10,system]
    Thread[Finalizer,8,system]
    Thread[Signal Dispatcher,9,system]
    Thread[Attach Listener,5,system]
    java.lang.ThreadGroup[name=main,maxpri=10]
        Thread[main,5,main]
        Thread[log4j mail appender,5,main]
[DEBUG][2009-08-25 08:57:54,386] - isSuccess:false

我希望知道一个系统的方法来找出原因。谢谢。


你是否捕获了被抛出的任何异常? - seth
没有任何异常。它只会返回false。 - janetsmith
你能详细说明一下你在这里使用多线程的情况吗?这听起来像是竞态条件,但是没有更多的信息,我无法猜测实际的故障点。 - Yuval
我在我的程序中没有创建任何新线程。我只是检查是否有未经我知晓的线程被创建。 - janetsmith
8个回答

34

文件重命名失败的原因可能是文件仍然处于打开状态。即使您关闭了文件,由于以下原因,它仍可能处于打开状态:

  1. 一个子进程继承了文件句柄
  2. 防病毒程序正在对文件进行扫描,因此将其保持打开状态
  3. 索引程序(如Google桌面或Windows索引服务)正在使用该文件

为找出是什么在让文件保持打开状态,请使用诸如FileMonHandle之类的工具。

更新:如果文件仅被保持打开了很短的时间(例如防病毒扫描),则Unlocker等工具可能无法解决问题。但是,如果javaw.exe显示为已打开该文件,则问题就在这里。


我正在使用Unlocker,但它只显示“javaw.exe”作为唯一的锁定程序。 :( - janetsmith
我认为像防病毒软件和索引程序这样的扫描应用程序不应该能够持有文件并防止其被更改或重命名...在WinXP中实际情况是这样吗? - Yuval
他们不会长时间保持文件打开状态,但通常会在文件更改后进行监视,并在文件更新后进行扫描。如果您写入一个文件,关闭它,然后尝试重命名它,那么此时文件可能仍然处于打开状态(尽管时间不长)。 - Vinay Sajip

3
如果没有抛出任何异常(我假设你应该会注意到),renameTo()只返回true或false,表示重命名是否成功,并且不提供任何其他信息。
由于这是Windows操作系统,失败很可能表示文件当前正在被使用。这可能是因为其他进程正在使用该文件,但更有可能的是,您的进程在完成写入后忘记关闭该文件。
还有可能是您传递了一个无效路径,或者在File构造函数中给出了不存在的路径。
只有在存在安全违规(SecurityException),或者您传递了一个 null 用于重命名文件时,renameTo()才会引发异常。

1
我知道它返回false,但它没有给出任何失败的原因。我已经关闭了所有的outputStream.close()并将其设置为null。但它仍然会随机失败。假设我生成了10个文件,file0.tmp ... file9.tmp,可能是file5.tmp无法更改为file5.txt。 - janetsmith

3
File o=new File("d:/old.txt");
File n=new File("d:/new.txt");
n.delete();
o.renameTo(n);

n.delete() : 如果文件(new.txt)存在,我们需要删除它。

o.rename(n) : 这样一来,文件(old.txt)就会被重命名为new.txt。


2
我已经做了那件事,但仍然从重命名中得到了错误的返回值。该文件已关闭,没有其他程序占用它。这就是Windows的问题。 - stu

2

重命名(renameTo)失败的三个主要原因(适用于Android,但您也可能会发现这很有用)!

1)如果您正在将文件夹从a位置移动到b位置,则目标文件夹可能是一个文件!使用destinationFolder.mkdirs()将其创建为文件!

2)目标文件夹可能已经存在!删除destinationFolder以便您可以使用renameTo将旧文件移动到那个新位置

3)将内部存储移动到外部存储需要权限,因为读写SD卡需要权限!


我通过谷歌找到了这个问题,第2个是我的问题。感谢帮助! - dj_bushido
3
把 "destinationFolder.mkdirs()" 改为创建文件而非文件夹!?哎? - EntangledLoops

2

我曾遇到类似问题,但是这是在Unix系统中出现的。
重命名操作随机失败。我尝试了3到4次重新启动进程,最终成功了。
顺便提一下,该文件是由同一个进程创建并进行重命名的。


0

0

我在Mac上遇到了同样的问题。我有一个进程,使用单个线程创建163,000个文件。如果已经存在文件,则会跳过其创建。为了避免部分文件问题,在写入文件时,它会先写入临时文件(... / dir / tmp.filename),然后重命名它(... / dir / filename)。

我曾经运行过一次(从IntelliJ内部),然后运行窗口消失了,这很奇怪。我重新启动了IntelliJ并再次运行它,并开始在我的一些文件重命名中出现错误(但不是所有文件都有)。结果发现,即使IntelliJ(启动它的应用程序)退出了,我的之前运行的java进程仍在运行。因此,我有两个进程正在寻找相同文件的存在并互相干扰。


-4

文件 f = new File(folder + file); 如果您已正确编写路径,请使用if进行验证。 f.exists(); 否则存在并返回false,请使用procMon进行验证是否已查看。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接