распаковать огромный файл gz в Java и производительность

Я распаковываю огромный файл gz в java, файл gz составляет около 2 ГБ, а разархивированный файл - около 6 ГБ. время от времени процесс распаковки занимал вечность (часы), иногда он заканчивался в разумные сроки (например, менее 10 минут или быстрее).
У меня довольно мощный компьютер (8 ГБ ОЗУ, 4 процессора), можно ли улучшить приведенный ниже код? или использовать совершенно другую библиотеку?
Также я использовал Xms256m и Xmx4g для vm.

public static File unzipGZ(File file, File outputDir) {
    GZIPInputStream in = null;
    OutputStream out = null;
    File target = null;
    try {
        // Open the compressed file
        in = new GZIPInputStream(new FileInputStream(file));

        // Open the output file
        target = new File(outputDir, FileUtil.stripFileExt(file.getName()));
        out = new FileOutputStream(target);

        // Transfer bytes from the compressed file to the output file
        byte[] buf = new byte[1024];
        int len;
        while ((len = in.read(buf)) > 0) {
            out.write(buf, 0, len);
        }

        // Close the file and stream
        in.close();
        out.close();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (in != null) {
            try {
                in.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        if (out != null) {
            try {
                out.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    return target;
}

person user121196    schedule 14.02.2011    source источник
comment
@ user121196: миллиарды и Java не очень хорошо сочетаются. Если у вас есть контроль над системой и если это блок Un * x, я бы подумал о вызове внешнего процесса здесь. Это неприятно, но есть причина, по которой программное обеспечение, управляющее действительно огромными файлами или очень большим количеством файлов (например, Git, Mercurial и т. д.), не написано на Java...   -  person Gugussee    schedule 14.02.2011
comment
В итоге я использовал собственный процесс gunzip для Linux, он даже быстрее, чем IOUtil.moveFile.   -  person user121196    schedule 19.02.2011
comment
Связанный вопрос: Как распаковать файл TAR с помощью Apache Commons.   -  person blong    schedule 17.11.2013


Ответы (3)


Я не знаю, сколько буферизации применяется по умолчанию, если таковая имеется, но вы можете попробовать обернуть как ввод, так и вывод в BufferedInputStream/BufferedOutputStream. Вы также можете попробовать увеличить размер буфера - 1 КБ - это довольно маленький буфер. Поэкспериментируйте с разными размерами, например. 16K, 64K и т. д. Это, конечно, должно сделать использование BufferedInputStream менее важным.

С другой стороны, я подозреваю, что это не совсем проблема. Если это иногда заканчивается за 10 минут, а иногда занимает часы, это говорит о том, что происходит что-то очень странное. Когда это занимает очень много времени, действительно ли это прогрессирует? Выходной файл увеличивается в размере? Использует ли он значительный процессор? Диск постоянно используется?

Одно замечание: поскольку вы закрываете in и out в блоках finally, вам не нужно делать это и в блоке try.

person Jon Skeet    schedule 14.02.2011

Если у вас 8 гигов ОЗУ, а входной файл занимает 2 гига, можно попробовать использовать файл отображения памяти. Вот пример того, как это сделать.

person aioobe    schedule 14.02.2011

Попробуйте использовать каналы из java.nio, у вас есть способ передачи байтов из файла в другие каналы. Тогда вам не придется копировать их самостоятельно. И это, вероятно, будет достаточно оптимизировано. См. FileInputStream.getChannel()

person jmg    schedule 14.02.2011