Как атомарно переименовать файл в Java, даже если dest файл уже существует?

В JavaSE ничего не будет сделано; вам придется искать сторонние библиотеки или писать свои собственные.

37
задан Sébastien RoccaSerra 27 February 2009 в 16:59
поделиться

6 ответов

На Linux (и я верю Солярису и другим операционным системам UNIX), File.renameTo Java () метод перезапишет целевой файл, если он будет существовать, но дело обстоит не так в соответствии с Windows.

, Чтобы быть кросс-платформенным, я думаю, что необходимо было бы использовать захват файла на resource.txt и затем перезаписать данные.

поведение блокировки файла зависимо от платформы. На некоторых платформах блокировка файла является консультацией, что означает, что, если приложение не проверяет на блокировку файла, ему не будут препятствовать получить доступ к файлу. На других платформах блокировка файла обязательна, что означает, что блокировка файла препятствует тому, чтобы любое приложение получило доступ к файлу.

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();

    // 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
    lock.release();

    // Close the file
    channel.close();
} catch (Exception e) {
}

Linux, по умолчанию, использует добровольную блокировку, в то время как Windows осуществляет его. Возможно, Вы могли обнаружить ОС и использовать renameTo () под UNIX с некоторым кодом блокировки для Windows?

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

Linux, после System V (см. Версию 3 Определения интерфейса System V (SVID)), позволяет биту sgid для файлов без группы, выполняются, разрешение отмечают файл для обязательной блокировки

13
ответ дан Grodriguez 10 October 2019 в 09:11
поделиться

Вот обсуждение, которое имеет отношение: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4017593

7
ответ дан TofuBeer 10 October 2019 в 09:11
поделиться

Как указано здесь , похоже, что Windows OS даже не поддерживает атомарный файл, переименовывают для более старых версий. Вероятно, что необходимо использовать некоторые ручные механизмы блокировки или некоторые транзакции. Для этого Вы могли бы хотеть смотреть в апачская транзакция свободного городского населения пакет.

2
ответ дан vlp 10 October 2019 в 09:11
поделиться

Если это должно быть межплатформенным, я предлагаю 2 опции:

  1. Реализация промежуточный сервис, который ответственен за все доступы к файлу. Здесь можно использовать несколько механизмов для синхронизации запросов. Каждое клиентское приложение Java получает доступ к файлу только через этот сервис.
  2. Создают управление файл каждый раз, когда необходимо выполнить, синхронизировал операции. Каждое приложение Java, которое получает доступ к файлу, является ответственной проверкой управление файл и ожидание, в то время как этот управление файл существует. (почти как семафор). Процесс, делающий удалить/переименовать операцию, ответственен за создание/удаление управление файл.
1
ответ дан bruno conde 10 October 2019 в 09:11
поделиться

Если цель переименовывания состоит в том, чтобы заменить resource.txt на лету , и Вы управляете всеми включенными программами, и , частота замены не высока, Вы могли сделать следующее.

Для открытий/читавшего файла:

  1. Открывают "resource.txt", если это перестало работать
  2. , Открывают "resource.old.txt", если это перестало работать
  3. , Открывают "resource.txt" снова, если это перестало работать
  4. , у Вас есть состояние ошибки.

Для замены файла:

  1. Переименовывают "resource.txt" к "resource.old.txt", тогда
  2. Переименовывают "resource.new.txt" к "resource.txt", тогда
  3. Удаляют "resource.old.txt".

, Который удостоверится, все Ваши читатели всегда находят правильный файл.

, Но, легче, должен был бы просто попробовать Ваше открытие в цикле, как:

InputStream inp=null;
StopWatch   tmr=new StopWatch();                     // made up class, not std Java
IOException err=null;

while(inp==null && tmr.elapsed()<5000) {             // or some approp. length of time
    try { inp=new FileInputStream("resource.txt"); }
    catch(IOException thr) { err=thr; sleep(100); }  // or some approp. length of time
    }

if(inp==null) {
     // handle error here - file did not turn up after required elapsed time
     throw new IOException("Could not obtain data from resource.txt file");
     }

... carry on
1
ответ дан Lawrence Dol 10 October 2019 в 09:11
поделиться

Многие люди отмечают, что это часто используется с перерывом как неловкий способ написания «goto». Это, вероятно, верно, если он записан непосредственно в функции.

В макросе, OTOH, сделать {что-то;}, пока (false) является удобным способом принудительно ввести точку с запятой после вызова макроса, абсолютно не допускается следование другому маркеру.

И еще одна возможность состоит в том, что либо когда-то там был цикл, либо ожидается добавление итерации в будущем (например, в тестовой разработке итерация не требовалась для прохождения тестов, но логично было бы закольцевать там, если бы функция должна была быть несколько более общей, чем требуется в настоящее время)

-121--687440-

Это просто извращение в то время как , чтобы получить сематику goto tidy-up без использования слова goto.

Это плохая форма, потому что при использовании другие петли внутри внешнего в то время как разрывы становятся неоднозначными для читателя. "Это должно выйти? или это предназначено только для того, чтобы вырваться из внутреннего цикла? "

-121--687436-

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

1
ответ дан 27 November 2019 в 04:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: