Произвольный доступ к сжатому файлу без использования 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, как это предлагается в ответах:
- Sun ZipFile.entries() всегда возвращает ZipEntries в порядке, в котором они встречаются в файле, тогда как apache commons ZipFile.getEntries () возвращает записи в случайном порядке. Это вызвало интересную ошибку, потому что некоторый код предполагал, что записи будут "в порядке".
2 ответа
Для этой задачи вы можете посмотреть на Apache Commons Compress, Apache Commons VFS или TrueZip. Все они должны быть совместимы с Java 1.4 и, вероятно, поддерживать необходимые вам функции.
Вы можете посмотреть на Apache Commons Compress, который работает с 1.4+, но я не знаю, выявляет ли он ту же ошибку под капотом или нет.