Как заблокировать файл с помощью java (если возможно)

У меня есть процесс Java, который открывает файл с помощью FileReader. Как я могу предотвратить открытие этого файла другим (Java) процессом или, по крайней мере, уведомить этот второй процесс о том, что файл уже открыт? Это автоматически приводит к тому, что второй процесс получает исключение, если файл открыт (что решает мою проблему), или мне нужно явно открывать его в первом процессе с каким-то флагом или аргументом?

Чтобы уточнить:

У меня есть приложение Java, которое перечисляет папку и открывает каждый файл в списке для его обработки. Он обрабатывает каждый файл за другим. Обработка каждого файла состоит из его чтения и выполнения некоторых вычислений на основе содержимого, и это занимает около 2 минут. У меня также есть другое приложение Java, которое делает то же самое, но вместо этого записывает в файл. Я хочу иметь возможность запускать эти приложения одновременно, чтобы сценарий выглядел следующим образом. ReadApp выводит список папок и находит файлы A, B, C. Он открывает файл A и начинает чтение. WriteApp выводит список папок и находит файлы A, B, C. Он открывает файл A, видит, что он открыт (по исключению или другим способом), и переходит к файлу B. ReadApp завершает файл A и переходит к B. Он видит, что он открыт и продолжает C. Очень важно, чтобы WriteApp не писал, пока ReadApp читает тот же файл, или наоборот. Это разные процессы.

Вы имеете в виду «процесс», как в процесс (две JVM) или поток (та же JVM). Влияние на ответ имеет первостепенное значение.

Stu Thompson 25.09.2008 10:55

проверьте пример кода, показывающий решение здесь: stackoverflow.com/a/58871479/5154619

Davi Cavalcanti 15.11.2019 09:33
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
122
2
166 930
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

Если вы можете использовать Java NIO (JDK 1.4 или выше), то я думаю, вы ищете java.nio.channels.FileChannel.lock()

FileChannel.lock ()

Может быть. Зависит от того, что OP имел в виду под словом «процесс». «Блокировки файлов устанавливаются от имени всей виртуальной машины Java. Они не подходят для управления доступом к файлу несколькими потоками внутри одной виртуальной машины».

Stu Thompson 25.09.2008 10:59

@Stu: Я знаю, что вы давно ответили на этот вопрос, но я надеюсь, что вы сможете уточнить, что вы имели в виду, когда сказали File locks are held on behalf of the entire Java virtual machine. They are not suitable for controlling access to a file by multiple threads within the same virtual machine.

Thang Pham 13.06.2011 19:35

@Harry Он цитирует документы: download.oracle.com/javase/6/docs/api/java/nio/channels/… Это означает, что он невидим для потоков, но влияет на другие процессы.

Artur Czajka 04.07.2011 18:02

@Harry: Чтобы добавить еще больше к этим некро-комментариям, представьте, что вы используете Java для обслуживания веб-сайтов с помощью Tomcat. У вас может быть много потоков, каждый из которых обслуживает один запрос из веб-браузера. Однако все они управляют одним и тем же механизмом блокировки файлов, как и многие повара на кухне. Один запрос может завершиться в середине второго, и внезапно ваш файл «разблокируется», пока вы все еще заняты чем-то, а затем какой-то другой процесс, такой как cronjob, может заблокировать его, и тогда вы неожиданно потеряли свой блокировка и ваш запрос не может быть завершен ...

Darien 09.07.2011 06:01

используйте java.nio.channels.FileLock вместе с java.nio.channels.FileChannel

Ответ принят как подходящий

FileChannel.lock - это, вероятно, то, что вам нужно.

try (
    FileInputStream in = new FileInputStream(file);
    java.nio.channels.FileLock lock = in.getChannel().lock();
    Reader reader = new InputStreamReader(in, charset)
) {
    ...
}

(Отказ от ответственности: код не компилируется и, конечно же, не тестируется.)

Обратите внимание на раздел «зависимости платформы» в Документация по API для FileLock.

Что еще более важно, поймите, что блокировка для JVM не подходит для блокировки файла для доступа отдельных потоков в пределах одной JVM.

Stu Thompson 25.09.2008 11:00

Вам нужен записываемый поток (например, FileOutputStream).

Javier 16.04.2013 16:55

@ Хавьер А ты? Я не пробовал. Из документации API ничего не выходит, что это требование. FileOutputStream вряд ли пригодится Reader.

Tom Hawtin - tackline 17.04.2013 16:52

Да, я пробовал, и он выдает NonWritableChannelException, потому что lock() пытается получить монопольную блокировку, но для этого требуется доступ на запись. Если у вас есть поток Вход, вы можете использовать lock(0L, Long.MAX_VALUE, false), который получает разделяемую блокировку и требует только доступа для чтения. Вы также можете использовать RandomAccessFile, открытый в режиме чтения-записи, если вам нужна эксклюзивная блокировка при чтении ... но это запретит одновременное чтение.

Javier 17.04.2013 18:16

@StuThompson, в Windows это фактически блокирует и другие потоки. В Linux это не блокируется, если другой процесс / поток также не использует явную блокировку.

Piotr Findeisen 29.04.2015 10:28

@ Хавьер Я думаю, вы хотите сказать lock(0L, Long.MAX_VALUE, true), а не lock(0L, Long.MAX_VALUE, false). последний аргумент там boolean shareddocs.oracle.com/javase/8/docs/api/java/nio/channels/…

john sullivan 23.01.2017 20:18

@PiotrFindeisen Что здесь подразумевается под явной блокировкой?

Dilip Raj Baral 05.06.2019 17:31

Используйте RandomAccessFile, получите его канал, затем вызовите lock (). Канал, предоставляемый потоками ввода или вывода, не имеет достаточных привилегий для правильной блокировки. Обязательно вызовите unlock () в блоке finally (закрытие файла не обязательно снимает блокировку).

можешь уточнить? Я имею в виду, насколько блокировка RandomAccess File лучше или безопаснее, чем потоковая

Paralife 25.09.2008 15:11

Ссылка на простой пример, размещенный ниже

Touko 27.08.2009 10:54

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

Kevin Day 28.08.2009 01:39

Возможно, это не то, что вы ищете, но чтобы взглянуть на проблему под другим углом ...

Могут ли эти два процесса Java получить доступ к одному и тому же файлу в одном приложении? Возможно, вы можете просто отфильтровать весь доступ к файлу с помощью одного синхронизированного метода (или, что еще лучше, с помощью JSR-166)? Таким образом, вы можете контролировать доступ к файлу и, возможно, даже ставить запросы доступа в очередь.

Два процесса не могут использовать синхронизацию, только два потока в одном процессе.

user207421 17.11.2015 08:55

Не используйте классы в пакете 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) {
    }

кстати, я записываю в файл блокировки текущий pid из этой подсказки stackoverflow.com/a/35885/1422630, поэтому после того, как я смогу прочитать его в новом экземпляре!

Aquarius Power 02.02.2015 23:22

этот выглядел хорошо, но не работает. Я получаю исключение OverlappingFileLockException каждый раз, даже если файл даже не существует

Gavriel 05.02.2015 13:11

Проблема произойдет, если вы вызовете tryLock после блокировки, как написано в примере

Igor Vuković 22.03.2016 15:09

Ниже приведен пример кода фрагмента для блокировки файла до тех пор, пока он не будет обработан 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();
        }
    }

}

Java 11 была выпущена в 2011 г.

Arneball 30.01.2021 22:59

Используйте это для 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);
    }

Другие вопросы по теме