Подтвердить что ты не робот

Чтение из ZipInputStream в ByteArrayOutputStream

Я пытаюсь прочитать один файл из java.util.zip.ZipInputStream и скопировать его в java.io.ByteArrayOutputStream (чтобы затем я мог создать java.io.ByteArrayInputStream и передать его сторонней библиотеке, которая завершит закрытие поток, и я не хочу, чтобы мой ZipInputStream закрывался).

Вероятно, у меня что-то не хватает, но я никогда не вхожу в цикл while:

ByteArrayOutputStream streamBuilder = new ByteArrayOutputStream();
int bytesRead;
byte[] tempBuffer = new byte[8192*2];
try {
    while ((bytesRead = zipStream.read(tempBuffer)) != -1) {
        streamBuilder.write(tempBuffer, 0, bytesRead);
    }
} catch (IOException e) {
    // ...
}

Что мне не хватает, что позволит мне копировать поток?

Edit:

Я должен был упомянуть ранее, что этот ZipInputStream не поступает из файла, поэтому я не думаю, что могу использовать ZipFile. Это происходит из файла, загруженного через сервлет.

Кроме того, я уже вызвал getNextEntry() на ZipInputStream, прежде чем перейти к этому фрагменту кода. Если я не пытаюсь копировать файл в другой InputStream (через OutputStream, упомянутый выше), и просто передайте ZipInputStream в мою стороннюю библиотеку, библиотека закрывает поток, и я ничего не могу сделать больше, подобно работе с остальными файлами в потоке.

4b9b3361

Ответ 1

Ваш цикл выглядит корректно - что возвращает следующий код (только по его собственному)?

zipStream.read(tempBuffer)

если он возвращает -1, тогда zipStream закрывается, прежде чем вы его получите, и все ставки отключены. Пришло время использовать ваш отладчик и убедиться, что то, что вам передается, действительно действительно.

Когда вы вызываете getNextEntry(), оно возвращает значение, и данные в записи значимы (т.е. getCompressedSize() возвращает допустимое значение)? ЕСЛИ вы просто читаете Zip файл, который не имеет встроенных записей zip-записи с включенным чтением, тогда ZipInputStream не будет работать для вас.

Некоторые полезные лакомые кусочки о формате Zip:

Каждый файл, встроенный в zip файл, имеет заголовок. Этот заголовок может содержать полезную информацию (такую ​​как сжатая длина потока, ее смещение в файле, CRC) - или он может содержать некоторые магические значения, которые в основном говорят: "Информация отсутствует в заголовке потока, вы должны проверить Zip post-amble '.

Каждый zip файл затем имеет таблицу, которая прикреплена к концу файла, который содержит все записи zip, вместе с реальными данными. Таблица в конце обязательна, и значения в ней должны быть правильными. Напротив, значения, встроенные в поток, не обязательно должны быть предоставлены.

Если вы используете ZipFile, он читает таблицу в конце zip. Если вы используете ZipInputStream, я подозреваю, что getNextEntry() пытается использовать записи, внедренные в поток. Если эти значения не указаны, то ZipInputStream не знает, как долго может быть поток. Алгоритм раздувания является самоограниченным (вам действительно не нужно знать несжатую длину выходного потока, чтобы полностью восстановить выход), но возможно, что версия Java этого читателя не справляется с этой ситуацией очень хорошо.

Я скажу, что довольно необычно иметь сервлет, возвращающий ZipInputStream (гораздо более распространенный способ получения инфляционного потока InfusionStream, если вы собираетесь получать сжатый контент.

Ответ 2

Вероятно, вы пытались читать с FileInputStream следующим образом:

ZipInputStream in = new ZipInputStream(new FileInputStream(...));

Этот wont работает, поскольку zip-архив может содержать несколько файлов, и вам нужно указать, какой файл читать.

Вы можете использовать java.util.zip.ZipFile и такую ​​библиотеку, как IOUtils из Apache Commons IO или ByteStreams из Guava, которые помогут вам в копировании потока.

Пример:

ByteArrayOutputStream out = new ByteArrayOutputStream();
try (ZipFile zipFile = new ZipFile("foo.zip")) {
    ZipEntry zipEntry = zipFile.getEntry("fileInTheZip.txt");

    try (InputStream in = zipFile.getInputStream(zipEntry)) {
        IOUtils.copy(in, out);
    }
}

Ответ 3

Я использую IOUtils из проекта сообщества.

IOUtils.copy(zipStream, byteArrayOutputStream);

Ответ 4

Вы можете реализовать свою собственную оболочку вокруг ZipInputStream, которая игнорирует close() и передает ее сторонней библиотеке.

thirdPartyLib.handleZipData(new CloseIgnoringInputStream(zipStream));


class CloseIgnoringInputStream extends InputStream
{
    private ZipInputStream stream;

    public CloseIgnoringInputStream(ZipInputStream inStream)
    {
        stream = inStream;
    }

    public int read() throws IOException {
        return stream.read();
    }

    public void close()
    {
        //ignore
    }

    public void reallyClose() throws IOException
    {
        stream.close();
    }
}

Ответ 5

Вам не хватает вызова

ZipEntry entry = (ZipEntry) zipStream.getNextEntry();

для размещения первого байта, декомпрессированного первой записи.

 ByteArrayOutputStream streamBuilder = new ByteArrayOutputStream();
 int bytesRead;
 byte[] tempBuffer = new byte[8192*2];
 ZipEntry entry = (ZipEntry) zipStream.getNextEntry();
 try {
     while ( (bytesRead = zipStream.read(tempBuffer)) != -1 ){
        streamBuilder.write(tempBuffer, 0, bytesRead);
     }
 } catch (IOException e) {
      ...
 }

Ответ 6

Я бы назвал getNextEntry() в ZipInputStream до тех пор, пока он не окажется в нужной записи (используйте ZipEntry.getName() и т.д.). Вызов getNextEntry() переместит "курсор" в начало возвращаемой записи. Затем используйте ZipEntry.getSize(), чтобы определить, сколько байтов вы должны прочитать с помощью zipInputStream.read().

Ответ 7

Непонятно, как вы получили zipStream. Он должен работать, когда вы получите его следующим образом:

  zipStream = zipFile.getInputStream(zipEntry)

Ответ 8

t неясно, как вы получили zipStream. Он должен работать, когда вы получите его следующим образом:

  zipStream = zipFile.getInputStream(zipEntry)

Если вы получаете ZipInputStream из ZipFile, вы можете получить один поток для библиотеки 3d-участников, пусть он его использует, и вы получите еще один входной поток с использованием кода раньше.

Помните, что входной поток является курсором. Если у вас есть все данные (например, ZipFile), вы можете запросить у него N курсоров.

Другим случаем является наличие только входного потока "GZip", только поток с заархивированным байтом. В этом случае буфер ByteArrayOutputStream имеет смысл.

Ответ 9

Пожалуйста, попробуйте приведенный ниже код

private static byte[] getZipArchiveContent(File zipName) throws WorkflowServiceBusinessException {

  BufferedInputStream buffer = null;
  FileInputStream fileStream = null;
  ByteArrayOutputStream byteOut = null;
  byte data[] = new byte[BUFFER];

  try {
   try {
    fileStream = new FileInputStream(zipName);
    buffer = new BufferedInputStream(fileStream);
    byteOut = new ByteArrayOutputStream();

    int count;
    while((count = buffer.read(data, 0, BUFFER)) != -1) {
     byteOut.write(data, 0, count);
    }
   } catch(Exception e) {
    throw new WorkflowServiceBusinessException(e.getMessage(), e);
   } finally {
    if(null != fileStream) {
     fileStream.close();
    }
    if(null != buffer) {
     buffer.close();
    }
    if(null != byteOut) {
     byteOut.close();
    }
   }
  } catch(Exception e) {
   throw new WorkflowServiceBusinessException(e.getMessage(), e);
  }
  return byteOut.toByteArray();

 }

Ответ 10

Проверьте, находится ли входной поток в попрошайничестве.

В противном случае, как реализация: я не думаю, что вам нужно писать в поток результатов во время чтения, если только вы не обрабатываете этот точный поток в другом потоке.

Просто создайте массив байтов, прочитайте входной поток, затем создайте выходной поток.