Файлы иногда перезаписываются, несмотря на проверку, чтобы предотвратить это - PullRequest
0 голосов
/ 10 апреля 2019

У меня есть код для работы с некоторым файлом:

Path path = ...;
if (!path.toFile().exists() || Files.size(path) == 0L) {
  Files.write(path, data, StandardOpenOption.CREATE);
}

Он работает почти всегда, но в некоторых случаях он переопределяет существующий файл, поэтому я получаю поврежденный файл со старыми данными, перезаписываемыми с новымиданные.Например, если содержимое файла было 00000000000000 и data равно AAA в приведенном выше коде, я получу файл с содержимым AAA00000000000.Доступ к файлу хорошо синхронизирован, поэтому только один поток может получить доступ к файлу, одновременно может быть запущен только один экземпляр приложения.Приложение работает на Heroku (это управляемая героем файловая система), я не могу воспроизвести такое же поведение на своем ноутбуке.

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

Ответы [ 2 ]

0 голосов
/ 10 апреля 2019

Ваш код содержит опасность для гонки, потому что он выполняет «взгляд перед прыжком», на который нельзя положиться.Между вашим предикатом

!path.toFile().exists() || Files.size(path) == 0L

, дающим true, который, по вашему мнению, означает , означает, что файл не имеет предыдущего содержимого, и выполнением Files.write для записи в файл, другой процесс (или поток) мог записать в файл.

0 голосов
/ 10 апреля 2019

Какое поведение требуется для существующего файла с данными?

  1. Отменить существующие данные

    Вы можете использовать CREATE и TRUNCATE_EXISTING вместе. На самом деле, может быть, вы ничего не должны использовать, так как по умолчанию для write () используется CREATE, TRUNCATE_EXISTING, WRITE, для документации .

  2. Сохранить существующие данные

    Вы можете открыть его в режиме APPEND, а не в режиме WRITE.

  3. Ничего не предпринимать, если файл уже существует и не пуст.

    Это сложно. Отчет с ненулевым размером вызывает беспокойство. Я бы предложил использовать CREATE_NEW (сбой, если существует), и если вы получаете исключение сбоя, прочитайте файл, чтобы увидеть, не является ли он пустым.

...