FileChannel.transferTo для большого файла в Windows - PullRequest
8 голосов
/ 11 сентября 2011

Использование Java NIO позволяет быстрее копировать файлы. Я нашел два вида метода в основном через Интернет, чтобы сделать эту работу.

public static void copyFile(File sourceFile, File destinationFile) throws IOException {
    if (!destinationFile.exists()) {
        destinationFile.createNewFile();
    }

    FileChannel source = null;
    FileChannel destination = null;
    try {
        source = new FileInputStream(sourceFile).getChannel();
        destination = new FileOutputStream(destinationFile).getChannel();
        destination.transferFrom(source, 0, source.size());
    } finally {
        if (source != null) {
            source.close();
        }
        if (destination != null) {
            destination.close();
        }
    }
}

В 20 очень полезных фрагментов кода Java для разработчиков Java Я нашел другой комментарий и хитрость:

public static void fileCopy(File in, File out) throws IOException {
    FileChannel inChannel = new FileInputStream(in).getChannel();
    FileChannel outChannel = new FileOutputStream(out).getChannel();
    try {
        // inChannel.transferTo(0, inChannel.size(), outChannel); // original -- apparently has trouble copying large files on Windows
        // magic number for Windows, (64Mb - 32Kb)
        int maxCount = (64 * 1024 * 1024) - (32 * 1024);
        long size = inChannel.size();
        long position = 0;
        while (position < size) {
            position += inChannel.transferTo(position, maxCount, outChannel);
        }
    } finally {
        if (inChannel != null) {
            inChannel.close();
        }
        if (outChannel != null) {
            outChannel.close();
        }
    }
}

Но я не нашел и не понял, что означает

"магическое число для Windows, (64Mb - 32Kb)"

В нем говорится, что inChannel.transferTo(0, inChannel.size(), outChannel) имеет проблемы в Windows, для этого метода оптимальным является байт 32768 (= (64 *1024* 1024) - (32 * 1024)).

Ответы [ 3 ]

7 голосов
/ 13 сентября 2011

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

Установка размера передачи более 1 МБ в любом случае довольно бессмысленна.

РЕДАКТИРОВАТЬ Ваша вторая версия имеет недостаток. Вы должны уменьшить size на сумму, переданную каждый раз. Это должно быть больше похоже на:

while (position < size) {
    long count = inChannel.transferTo(position, size, outChannel);
    if (count > 0)
    {
        position += count;
        size-= count;
    }
}
0 голосов
/ 04 января 2014

Я прочитал, что это для совместимости с операционной системой Windows 2000.

Источник: http://www.rgagnon.com/javadetails/java-0064.html

Цитата: В win2000, TransferTo () не передает файлы размером> 2 ^ 31-1 байт. он выдает исключение «java.io.IOException: Недостаточно системных ресурсов для завершения работы запрошенного сервиса». Обходной путь - копировать в цикле по 64 МБ каждый раз, пока не останется больше данных.

0 голосов
/ 11 сентября 2011

По-видимому, имеются отдельные примеры того, что попытки передачи более 64 МБ за один раз в определенных версиях Windows приводят к медленному копированию. Отсюда проверка: это, кажется, результат некоторых деталей базового нативного кода, который реализует операцию transferTo в Windows.

...