У меня есть процесс Java, который открывает файл с помощью FileReader. Как я могу предотвратить открытие этого файла другим (Java) процессом или, по крайней мере, уведомить этот второй процесс о том, что файл уже открыт? Это автоматически приводит к тому, что второй процесс получает исключение, если файл открыт (что решает мою проблему), или мне нужно явно открывать его в первом процессе с каким-то флагом или аргументом?
Чтобы уточнить
У меня есть приложение Java, которое перечисляет папку и открывает каждый файл в списке для его обработки. Он обрабатывает каждый файл за другим. Обработка каждого файла состоит из его чтения и выполнения некоторых вычислений на основе содержимого, и это занимает около 2 минут. У меня также есть другое приложение Java, которое делает то же самое, но вместо этого записывает в файл. Я хочу иметь возможность запускать эти приложения одновременно, чтобы сценарий выглядел следующим образом. ReadApp выводит список папок и находит файлы A, B, C. Он открывает файл A и начинает чтение. WriteApp выводит список папок и находит файлы A, B, C. Он открывает файл A, видит, что он открыт (по исключению или другим способом), и переходит к файлу B. ReadApp завершает файл A и переходит к B. Он видит, что он открыт и продолжает C. Очень важно, чтобы WriteApp не писал, пока ReadApp читает тот же файл, или наоборот. Это разные процессы.
Ответ 1 · рейтинг 119 · Tom Hawtin - tackline
FileChannel.lock - это, вероятно, то, что вам нужно.
try (
FileInputStream in = new FileInputStream(file);
java.nio.channels.FileLock lock = in.getChannel().lock();
Reader reader = new InputStreamReader(in, charset)
) {
...
}
(Отказ от ответственности: код не компилируется и, конечно же, не тестируется.)
Обратите внимание на раздел "зависимости платформы" в Документация по API для FileLock.
Ответ 2 · рейтинг 62 · ayengin
Не используйте классы в пакетеjava.io, вместо этого используйте пакет java.nio. Последний имеет FileLock класс. Вы можете применить блокировку к FileChannel.
try {
// Get a file channel for the file
File file = new File("filename");
FileChannel channel = new RandomAccessFile(file, "rw").getChannel();
// Use the file channel to create a lock on the file.
// This method blocks until it can retrieve the lock.
FileLock lock = channel.lock();
/*
use channel.lock OR channel.tryLock();
*/
// Try acquiring the lock without blocking. This method returns
// null or throws an exception if the file is already locked.
try {
lock = channel.tryLock();
} catch (OverlappingFileLockException e) {
// File is already locked in this thread or virtual machine
}
// Release the lock - if it is not null!
if( lock != null ) {
lock.release();
}
// Close the file
channel.close();
} catch (Exception e) {
}
Ответ 5 · рейтинг 5 · pkaeding
Возможно, это не то, что вы ищете, но чтобы взглянуть на проблему под другим углом ...
Могут ли эти два процесса Java получить доступ к одному и тому же файлу в одном приложении? Возможно, вы можете просто отфильтровать весь доступ к файлу с помощью одного синхронизированного метода (или, что еще лучше, используя JSR-166)? Таким образом, вы можете контролировать доступ к файлу и, возможно, даже ставить запросы доступа в очередь.
Ответ 6 · рейтинг 3 · Kevin Day
Используйте RandomAccessFile, получите его канал, затем вызовите lock (). Канал, предоставляемый потоками ввода или вывода, не имеет достаточных прав для правильной блокировки. Обязательно вызовите unlock () в блоке finally (закрытие файла не обязательно снимает блокировку).
Ответ 7 · рейтинг 1 · Ajay Kumar
Ниже приведен пример кода фрагмента для блокировки файла до тех пор, пока он не будет обработан JVM.
public static void main(String[] args) throws InterruptedException {
File file = new File(FILE_FULL_PATH_NAME);
RandomAccessFile in = null;
try {
in = new RandomAccessFile(file, "rw");
FileLock lock = in.getChannel().lock();
try {
while (in.read() != -1) {
System.out.println(in.readLine());
}
} finally {
lock.release();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Ответ 8 · Vamsi
Используйте это для unix, если вы переносите с помощью winscp или ftp:
public static void isFileReady(File entry) throws Exception {
long realFileSize = entry.length();
long currentFileSize = 0;
do {
try (FileInputStream fis = new FileInputStream(entry);) {
currentFileSize = 0;
while (fis.available() > 0) {
byte[] b = new byte[1024];
int nResult = fis.read(b);
currentFileSize += nResult;
if (nResult == -1)
break;
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("currentFileSize=" + currentFileSize + ", realFileSize=" + realFileSize);
} while (currentFileSize != realFileSize);
}