Распаковка большого zip-архива, OutOfMemoryException, ZipArchiveInputStream, ByteArrayInputStream и попытка не зависеть от объема архива

167
24 ноября 2018, 03:40

Стоит задача считывать большие zip-архивы (от 500Мб и выше).

Есть наброски кода, который должен это делать. Но при попытке получаю:

java.lang.OutOfMemoryException: Java heap space.

Разбираюсь. Подозреваю, что надо оптимизировать код или сам алгоритм. Буду признателен за подсказки.

Собственно код:

inputStream = (ByteArrayInputStream) fileDataHandler.getContent();
byte archive[] = IOUtils.toByteArray(inputStream);
String docPath = doc.getUri().replace('\\', '/');
if(docPath.endsWith("/")) {
   docPath = docPath.substring(0, docPath.length()-1);
}
ZipArchiveEntry ze;
Map<String, byte[]> files = new HashMap<String, byte[]>();
ZipArchiveInputStream zis = null;
try{
   zis = new ZipArchiveInputStream(new ByteArrayInputStream(archive), "cp886", true);
   while((ze = zis.getNextZipEntry()) != null) {
      if(!ze.isDirectory()) {
         byte[] toByteArray = IOUtils.toByteArray(zis);
         files.put(docPath + "/" ze.getName().replace('\\', '/'), toByteArray);
         //some checking for file validating
      }
   }
} catch(IOException ioe) {
Answer 1

Сложно придумать задачу, при которой вам обязательно нужно держать весь архив в памяти. Вот так, например, можно посчитать хеш от всех файлов в архиве:

FileInputStream file = new FileInputStream("archive.zip");
MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
ZipArchiveEntry ze;
ZipArchiveInputStream zis = null;
byte[] buffer = new byte[1024];
try {
    zis = new ZipArchiveInputStream(file, "cp886", true);
    while ((ze = zis.getNextZipEntry()) != null) {
        if (!ze.isDirectory()) {
            int read;
            while ((read = zis.read(buffer, 0, buffer.length)) != -1) {
                sha256.update(buffer, 0, read);
            }
        }
    }
} catch (IOException ioe) {
    System.out.println("error");
}
byte[] hash = sha256.digest();

Что бы посчитать/проверить что-то другое, вам придется снова открывать файл с архивом. Посчитать размер файлов также можно без затрат памяти изменив код в середине:

int fileSize = 0;
int read;
while ((read = zis.read(buffer, 0, buffer.length)) != -1) {
    fileSize += read;
}
READ ALSO
Вопрос про наследование

Вопрос про наследование

Здравствуйте, код выдает 0 9Подскажите пожалуйста, почему если поменять модификатор метода initialize() в классе А на private, то получаем 6 9 ? Инициализация...

156
Как пользоваться Selenium на Android?

Как пользоваться Selenium на Android?

как пользоваться Selenium на Android, как заходить на сайта не открывая браузер ?

208
Оптимизация, записи в файл

Оптимизация, записи в файл

Что быстрее запишется, вывод разделенный на файлы или при записи в один файл?

148
Box2D в LibGDX и просто Box2D, в чем разница?

Box2D в LibGDX и просто Box2D, в чем разница?

Некоторое непонимание появилось при просмотре обучающих видеоЕсть ли разница между просто установленным Box2D и Box2D, который можно выборочно...

133