Произвольный доступ к сжатому файлу без использования ZipFile (поскольку в ZipFile есть серьезная ошибка)

Я знаю, я знаю, кто хотел бы сжимать или распаковывать большие файлы в Java. Совершенно неразумно. На данный момент приостановите неверие и предположите, что у меня есть веская причина для распаковки большого zip-файла.

Проблема 1: в ZipFile есть ошибка (ошибка # 6280693), Sun исправила это в Java 1.6 (Mustang). Исправление не является полезным, поскольку наше программное обеспечение должно поддерживать Java 1.4. Баг, насколько я понимаю, работает так. Когда выполняется следующий код, Java выделяет кусок памяти, достаточно большой, чтобы вместить весь файл.

ZipFile zipFile = new ZipFile("/tmp/myFile.zip");

Если /tmp/myFile.zip равен 4 ГБ, Java выделяет 4 ГБ. Это вызывает исключение из кучи. Размер кучи +4 ГБ, к сожалению, не является приемлемым решением. знак равно

Решение проблемы 1: Используйте ZipInputStream, чтобы обрабатывать файл как поток и, таким образом, уменьшать и контролировать объем памяти.

byte[] buf = new byte[1024];
FileInputStream fs = new FileInputStream("/tmp/myFile.zip")
ZipInputStream zipIn = new ZipInputStream(fs);

ZipEntry ze = zipIn.getNextEntry();

while (ze != null){
  while ((int cr = zipIn.read(buf, 0, 1024)) > -1) 
    System.out.write(buf, 0, len);
  ze = zipIn.getNextEntry();
}

Проблема 2: Я хотел бы получить доступ к ZipEntries в случайном порядке. То есть я хотел бы распаковать только один ZipEntry без необходимости поиска по всему потоку. В настоящее время я создаю список zipEntries, который называется zes:

        ZipInputStream zin = new ZipInputStream("/tmp/myFile.zip");

        ZipEntry ze = zin.getNextEntry();
        List<ZipEntry> zes = new ArrayList<ZipEntry>();

        while(ze!=null){
            zes.add(ze);
            ze = zin.getNextEntry();
        }

Затем, когда мне нужно распаковать конкретный zipEntry, я повторяюсь по всем zipEntries, пока не найду соответствующий zipEntry, который затем распакую.

        ZipEntry ze = in.getNextEntry();
        while (! ze.getName().equals(queryZe.getName())){
            ze = zin.getNextEntry();
        }

        int cr;

        while ((cr = zin.read(buf)) > -1) 
            System.out.write(buf, 0, cr);

Вопрос: ZipFile имеет возможность произвольного доступа к ZipEntries.

new BufferedInputStream(zipFile.getInputStream(zipEntry));

Как я могу получить эту же способность без использования ZipFile?

Обратите внимание, что ZipInputStream имеет довольно странное поведение.

Особенно хорошую документацию по java и ZipFiles можно найти здесь:

http://commons.apache.org/compress/zip.html

Замечания по замене замены Sun ZipFile на Apache Commons ZipFile, как это предлагается в ответах:

  1. Sun ZipFile.entries() всегда возвращает ZipEntries в порядке, в котором они встречаются в файле, тогда как apache commons ZipFile.getEntries () возвращает записи в случайном порядке. Это вызвало интересную ошибку, потому что некоторый код предполагал, что записи будут "в порядке".

2 ответа

Решение

Для этой задачи вы можете посмотреть на Apache Commons Compress, Apache Commons VFS или TrueZip. Все они должны быть совместимы с Java 1.4 и, вероятно, поддерживать необходимые вам функции.

Вы можете посмотреть на Apache Commons Compress, который работает с 1.4+, но я не знаю, выявляет ли он ту же ошибку под капотом или нет.

Другие вопросы по тегам