Почему StandardOpenOption.DELETE_ON_CLOSE не закрывает исходный файл FileChannel? - PullRequest
2 голосов
/ 02 марта 2020

У нас есть метод в Java, который должен удалять исходный файл при вызове его метода close.

private void appendFile(Path destination, Path source) {

    try (FileChannel sourceChannel = FileChannel.open(source, StandardOpenOption.READ, StandardOpenOption.DELETE_ON_CLOSE);
         FileChannel destinationChannel = FileChannel.open(destination, StandardOpenOption.WRITE, StandardOpenOption.APPEND)) {
        destinationChannel.transferFrom(sourceChannel, destinationChannel.size(), sourceChannel.size());
    } catch (IOException ex) {
       // Do something with this exception
    }
}

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

Может ли кто-нибудь помочь нам с этим?

Ответы [ 2 ]

0 голосов
/ 28 апреля 2020

У нас была похожая проблема около 2015 года, после того, как пользователь на Win7 / x64 регулярно находил оставшиеся файлы, которые не были удалены после завершения программы. После некоторых исследований и проб и ошибок мы обнаружили, что это произошло только с файлами, которые недавно были сопоставлены с памятью, и исправили это, избегая сопоставления памяти с файлами, которые мы хотели удалить скоро / позже.

FileChannelImpl.transferFromFileChannel Память отображает источник для передачи. (Зависит от вашей JVM - я основываю это на OpenJDK.) Несмотря на то, что JVM очищает после копирования путем отмены сопоставления, тем самым делая недействительным созданное представление, ОС может отложить фактическую очистку до другого момента времени. Пока этого не происходит, файл имеет действующую (но недоступную) карту памяти, которая может препятствовать удалению ссылок.

Похоже, этот вопрос связан с: Как правильно закрыть MappedByteBuffer?

Для ссылка: jdk11 / sun.nio.ch.FileChannelImpl # TransferFromFileChannel

private long transferFromFileChannel(FileChannelImpl src,
                                     long position, long count)
    throws IOException
{
    if (!src.readable)
        throw new NonReadableChannelException();
    synchronized (src.positionLock) {
        long pos = src.position();
        long max = Math.min(count, src.size() - pos);

        long remaining = max;
        long p = pos;
        while (remaining > 0L) {
            long size = Math.min(remaining, MAPPED_TRANSFER_SIZE);
            // ## Bug: Closing this channel will not terminate the write
            MappedByteBuffer bb = src.map(MapMode.READ_ONLY, p, size);
            try {
                long n = write(bb, position);
                assert n > 0;
                p += n;
                position += n;
                remaining -= n;
            } catch (IOException ioe) {
                // Only throw exception if no bytes have been written
                if (remaining == max)
                    throw ioe;
                break;
            } finally {
                unmap(bb);
            }
        }
        long nwritten = max - remaining;
        src.position(pos + nwritten);
        return nwritten;
    }
}
0 голосов
/ 02 марта 2020

Из StandardOpenOption.DELETE_ON_CLOSE документации по опции:

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

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

Таким образом, это всего лишь лучшее усилие , а не 100% гарантия того, что он будет удален. Может быть, он еще открыт другим писателем?

...