Проверьте, заблокирован ли файл в 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;
}