Поврежденный zip-файл с использованием ZipOutputStream

Я пытаюсь создать zip-файл, чтобы иметь возможность отправлять несколько файлов по http.

Моя проблема в том, что сгенерированный Zip-файл поврежден до и после отправки файла. Проблема в том, что я не могу найти, что я сделал неправильно, так как я не получаю никаких ошибок внутри консоли.

Итак, у кого-нибудь есть идеи, что мой сгенерированный zip-файл поврежден?

Это мой код:

  OutputStream responseBody = t.getResponseBody();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ZipOutputStream zos = new ZipOutputStream(baos);


            int counter = 1;
            for (PDDocument doc : documents)
            {
                ZipEntry zipEntry = new ZipEntry("document" + counter);
                zos.putNextEntry(zipEntry);
                ByteArrayOutputStream docOs = new ByteArrayOutputStream();
                doc.save(docOs);
                docOs.close();
                zos.write(docOs.toByteArray());
                zos.closeEntry();
                zos.finish();
                zos.flush();

                counter++;
            }
            zos.close();
            baos.close();


            responseBody.write(baos.toByteArray());
            responseBody.flush();

Спасибо за помощь !


person Michel Melhem    schedule 24.08.2020    source источник
comment
Если ваша цель - отправить несколько файлов, а не заархивировать их конкретно, вы можете использовать multipart/form-data, возможно, с частичным сжатием.   -  person dave_thompson_085    schedule 25.08.2020


Ответы (1)


Вам нужно удалить zos.finish() из цикла, поскольку он завершает записи ZIP, так как он обрабатывается zos.close() в конце потока.

Для очень больших потоков лучше отправлять ZIP напрямую в responseBody, минуя ByteArrayOutputStream буфер памяти.

Если у вас все еще есть проблемы, проверьте, установлен ли тип содержимого вывода. Может быть проще выполнить отладку, временно записав byte[] в файл, чтобы проверить формат ZIP, который вы отправляете:

Files.write(Path.of("temp.zip"), baos.toByteArray());

В этой схеме ниже показана отправка простого ZIP-файла через http (из сервлета настройте первые две строки на соответствующие вызовы для t). Это может помочь вам проверить, какой шаг вашего кода вызывает повреждение, если вы вернетесь к добавлению собственных объектов документа внутри цикла:

// MUST set response content type:
// resp.setContentType("application/zip");
OutputStream out = resp.getOutputStream(); // or t.getResponseBody();
try(ZipOutputStream zos = new ZipOutputStream(out))
{
    while (counter-- > 0)
    {
        ZipEntry zipEntry = new ZipEntry("document" + counter+".txt");
        zos.putNextEntry(zipEntry);
        zos.write(("This is ZipEntry: "+zipEntry.getName()+"\r\n").getBytes());
    }
}
person DuncG    schedule 24.08.2020
comment
даже после этих модификаций zip все еще поврежден @DuncG - person Michel Melhem; 24.08.2020
comment
Если zos.finish() находится внутри цикла, то ZIP будет содержать только первую запись. - person DuncG; 24.08.2020
comment
@MichelMelhem DuncG абсолютно прав в том, что вам нужно избавиться от каждого отдельного ByteArrayOutputStream. Вы душите производительность вашей программы! Просто оберните тело вывода ответа в ZipOutputStream и напишите прямо в него. - person VGR; 24.08.2020