Java中如何检查文件是否被锁定

34

我的Java程序需要读取一个可能被其他写入程序锁定的文件。我需要检查文件是否被锁定,如果是,则等待直到它释放。如何实现这一点?

该Java程序正在运行在Windows 2000服务器上。


1
参见:https://dev59.com/gHRB5IYBdhLWcg3wH0SW - erickson
参见:https://dev59.com/03VD5IYBdhLWcg3wAGiD - erickson
10个回答

39

应该在Windows中工作:

File file = new File("file.txt");
boolean fileIsNotLocked = file.renameTo(file);

3
这是唯一对我有效的答案。小小的注意事项是:它明显地实际上重命名了文件。对于我的目的来说,这没问题,但人们应该意识到这一点。 - Michael A. Schaffrath
被接受的答案对我没有用,但这个答案有用。谢谢。 - Louis
太棒了。对于我的目的来说,在Linux中也可以工作,因为即使文件被其他进程打开,也可以写入文件。 - Eric Duminil
很明显,这会导致在声明布尔值后使用信息来访问或不访问文件之间产生竞争条件,例如检查文件是否正在使用时,同时另一个进程访问该文件,然后您尝试访问并遇到麻烦。我仍然觉得这个回答有用。 - Koenigsberg
算了,这对我完全没用。我正在使用不同的进程锁定一个文件,然后使用它来检查文件是否被另一个进程使用,但它错误地返回了“false”。Java 11,Win11。 - Koenigsberg

15

在Windows下使用Sun的JVM,FileLocks应该是能够正常工作的,尽管JavaDocs对其可靠性描述得相当模糊(与系统相关)。

然而,如果你的Java程序只需要识别某些“其他”程序是否锁定了文件,那么你不需要费力去处理FileLocks,而是可以尝试写入文件,如果文件已被锁定,则写入会失败。最好在实际系统上尝试一下,但我看到以下行为:

File f = new File("some-locked-file.txt");
System.out.println(f.canWrite()); // -> true
new FileOutputStream(f); // -> throws a FileNotFoundException

这很奇怪,但是如果你不把平台独立性看得太高,并且你的系统显示相同的行为,你可以将其组合在一个实用函数中。

当前的 Java 版本中,不幸的是没有办法得知文件状态的变化,所以如果你需要等待文件写入,你必须不时地尝试检查其他进程是否释放了文件锁。我不确定,但是在 Java 7 中,可能可以使用新的 WatchService 来获取这样的变化通知。


7
这种行为在Windows中是不正确的,因为File.canWrite()只检查MS-DOS只读标志,而不检查文件的访问控制列表(ACLs)。因此,它会对您无法写入的文件给出错误的结果。 - Hakanai
1
感谢 Trejkaz!这种方法在 Windows 上的行为很奇怪。我试图在 watchevent 之后验证文件是否准备就绪,并且这些方法始终返回 true,即使文件的复制尚未完成。 - Nereis
Windows中的文件锁仅为建议性质。不能保证其他文件无法读取/写入已锁定的文件。 - The Coordinator
canWrite 有两个注意事项。正如 @Trejkaz 所说,它只是检查标志,但 JVM 可能也有特殊权限来覆盖此标志。 - Pieter De Bie
2
注意:如果这是一个已存在的文件,则会删除该文件中的所有数据。 - TechJ
1
使用new FileOutputStream(file, true)以保留文件内容(如果文件存在)。 - Dimitar II

6
在所有使用该文件的Java应用程序中使用FileLock,并使它们在同一个JVM中运行。否则,这不能得到可靠的实现。

4

如果可能有多个进程(可以是Java和非Java的混合)在使用文件,则使用文件锁定(FileLock)。成功使用文件锁的关键是记住它们仅仅是“建议性的”。如果您忘记了,锁定将被保证可见,但它不会阻止您对文件进行操作。所有访问该文件的进程都应该设计为使用锁定协议。


2

最好的方法是使用FileLock,但在我的情况下(jdk 1.6),我尝试并成功了:

public static boolean isFileUnlocked(File file) {
        try {
            FileInputStream in = new FileInputStream(file);
            if (in!=null) in.close();
            return true;
        } catch (FileNotFoundException e) {
            return false;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return true;
    }

1
我使用了FileLock,但是当尝试为FileLock创建通道时,我遇到了相同的FileNotFoundException。因此,即使使用FileLock,您仍然可能会在FileNotFoundException上出现问题(至少对于Excel类型锁定),因此我认为这是解决问题的方法。 - EngineerWithJava54321
不太相关于问题,但我只是想添加一点,检查 if (in != null) 绝对不必要,这个条件将始终为真。 - bvdb

2

您可以尝试对文件进行独占锁定。只要无法获得独占锁定,就表示另一个程序已经对该文件进行了锁定(独占或共享)。


2

我尝试了 @vlad 提供的方法,在 Windows 上访问 Linux Smb 共享文件,对于像 Excel 这样的锁定功能已经足够了,但对于一些编辑器则不行。为了测试两种情况,我添加了第二部分(重命名)。

Original Answer 翻译成“最初的回答”。

public static boolean testLockFile(File p_fi) {
    boolean bLocked = false;
    try (RandomAccessFile fis = new RandomAccessFile(p_fi, "rw")) {
      FileLock lck = fis.getChannel().lock();
      lck.release();
    } catch (Exception ex) {
      bLocked = true;
    }
    if (bLocked)
      return bLocked;
    // try further with rename
    String parent = p_fi.getParent();
    String rnd = UUID.randomUUID().toString();
    File newName = new File(parent + "/" + rnd);
    if (p_fi.renameTo(newName)) {
      newName.renameTo(p_fi);
    } else
      bLocked = true;
    return bLocked;
  }

2
对于Windows系统,您还可以使用如下方法:

最初的回答:

new RandomAccessFile(file, "rw")

如果文件被独占锁定(例如由MS Word),将会出现异常:java.io.FileNotFoundException: <fileName> (The process cannot access the file because it is being used by another process)。这样,您就不需要仅为检查而打开/关闭流。
注意 - 如果文件没有被独占锁定(例如在Notepad++中打开),则不会出现异常。

1

改进了Amjad Abdul-Ghani的答案,我发现在尝试从文件中读取数据之前没有产生任何错误。

public static boolean isFilelocked(File file) {
     try {
         try (FileInputStream in = new FileInputStream(file)) {
             in.read();
             return false;
         }
     } catch (FileNotFoundException e) {
         return file.exists();
     } catch (IOException ioe) {
         return true;
     }
 }

0

仅在Windows上测试过: 您可以按照增强的venergiac答案检查文件是否被锁定: 检查(file.exist())文件是否存在,但如果出现FileNotFoundException,则表示已被锁定! 您将注意到此消息(进程无法访问文件,因为另一个进程正在使用它)

        public static boolean isFilelocked(File file) {
                try {

                    FileInputStream in = new FileInputStream(file);
                    in.close();
                    return false;
                } catch (FileNotFoundException e) {
                    if(file.exist()){ 
                       return true;
                     }
                     return false;
                } catch (Exception e) {
                    e.printStackTrace();
                }

                return false;
            }

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