Проверьте, заблокирован ли файл в Java

Моя Java-программа хочет прочитать файл, который может быть заблокирован другой программой, записывающей в него. Мне нужно проверить, заблокирован ли файл, и если да, дождаться его освобождения. Как мне этого добиться?

Программа Java работает на сервере Windows 2000.

8 ответов

Решение

Под 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, чтобы быть в курсе таких изменений.

Должно работать в Windows:

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

Использовать FileLock во всех приложениях Java, использующих этот файл, и запускать их в одной и той же JVM. В противном случае это не может быть сделано надежно.

Если файл использует несколько процессов (которые могут быть смесью Java и не-Java), используйте FileLock, Ключ к успешному использованию блокировок файлов - помнить, что они только "рекомендательные". Блокировка гарантированно будет видимой, если вы проверите ее, но она не помешает вам что-то сделать с файлом, если вы забудете. Все процессы, которые обращаются к файлу, должны быть разработаны для использования протокола блокировки.

Для 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++), исключений не будет.

Вы можете попытаться получить эксклюзивную блокировку файла. Пока исключительная блокировка не может быть получена, другая программа имеет блокировку (эксклюзивную или общую) для файла.

Лучший способ - использовать 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;
    }

Я попробовал комбинацию ответов (@vlad) на окнах с доступом к Linux Smb share, и это сработало для меня. Первой части было достаточно для блокировки, как в Excel, но не для некоторых редакторов. Я добавил вторую часть (переименовать) для тестирования обеих ситуаций.

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;
  }

Улучшенный ответ Амджада Абдул-Гани, я обнаружил, что никакой ошибки не было получено до попытки чтения из файла

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;
     }
 }

Протестировано только для 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;
            }
Другие вопросы по тегам