Как гарантировать атомарное перемещение или исключение файла в Java?

в одном из моих проектов у меня есть параллельный доступ на запись к одному файлу в одной JRE и я хочу обработать это, сначала записав во временный файл, а затем переместив этот временный файл в цель с помощью атомарного перемещения. Меня не волнует порядок доступа к записи или что-то в этом роде, все, что мне нужно гарантировать, это то, что в любой момент времени один файл можно использовать. Я уже знаю о файлах.move и так далее, моя проблема в том, что я посмотрел хотя бы одну реализацию для этого метода и это возникли некоторые сомнения в том, действительно ли реализации гарантируют атомные ходы. Пожалуйста, посмотрите на следующий код:

файлы.перейти на GrepCode для OpenJDK

1342        FileSystemProvider provider = provider(source);
1343        if (provider(target) == provider) {
1344            // same provider
1345            provider.move(source, target, options);
1346        } else {
1347            // different providers
1348            CopyMoveHelper.moveToForeignTarget(source, target, options);
1349        }

проблема в том, что опция ATOMIC_MOVE рассматривается не во всех случаях, но местоположение исходного и целевого пути-это единственное, что имеет значение в первую очередь. Это не то, что я хочу, и как я понимаю документацию:

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

приведенный выше код явно нарушает эту документацию, потому что он возвращается к стратегии копирования-удаления без распознавания ATOMIC_MOVE вообще. Исключение было бы идеально Хорошо в моем случае, потому что с этим хостер нашего сервиса может изменить свою настройку, чтобы использовать только одну файловую систему, которая поддерживает атомарные перемещения, так как это то, что мы ожидаем в системных требованиях в любом случае. Я не хочу иметь дело с тем, что вещи молча терпят неудачу только потому, что реализация использует стратегию копирования-удаления, которая может привести к повреждению данных в целевом файле. Поэтому, насколько я понимаю, просто небезопасно полагаться на файлы.переместить для атомарных операций, потому что он не всегда терпит неудачу, если они не поддерживаются, но реализации могут вернуться к стратегии копирования-удаления.

является ли такое поведение ошибкой в реализации и должно быть подано или документация позволяет такое поведение, и я понимаю это неправильно? Имеет ли значение вообще, если я теперь уже знаю, что такие, возможно, сломанные реализации используются там? В этом случае мне нужно будет синхронизировать доступ на запись самостоятельно...

2 ответов


вы смотрите не на то место. Если поставщики файловой системы не совпадают, операция будет делегирована moveToForeignTarget Как вы видели в фрагменте кода, который вы опубликовали. Метод moveToForeignTarget однако будет использовать метод convertMoveToCopyOptions (обратите внимание на говорящее имя...) для получения необходимых параметров копирования для переведенной операции. И convertMoveToCopyOptions появится AtomicMoveNotSupportedException если встречается ATOMIC_MOVE опция, поскольку нет способа преобразовать эту опцию перемещения в действительную копию выбор.

так что нет причин для беспокойства, и в целом рекомендуется избегать поспешного вывода от просмотра всего лишь десяти строк кода (особенно, когда не пробовал ни одного теста)...


стандартная библиотека Java не предоставляет способ выполнения атомарного перемещения во всех случаях.

файлы.move () не гарантирует атомарный ход. Вы можете пройти ATOMIC_MOVE Как вариант, но если движение не может быть выполнено как атомарная операция, AtomicMoveNotSupportedException выбрасывается (это тот случай, когда целевое местоположение находится в другом хранилище файлов и требует, чтобы файл был скопирован).

вы должны реализовать себя, если вам это действительно нужно. Одним из решений может быть поймать AtomicMoveNotSupportedException а затем сделайте следующее: попробуйте переместить файл без ATOMIC_MOVE опция, но поймать исключения и удалить цель, если произошла ошибка во время копирования.