Сохраняется ли ZipEntry после закрытия ZipFile?

#java #inputstream #zipfile

#java #входной поток #zip

Вопрос:

В настоящее время у меня вероятная утечка ресурсов в моей библиотеке из-за того, что я держу ZipFile открытым, чтобы возвращаемый входной поток для определенного ZipEntry не был закрыт. Однако закрытие возвращаемого InputStream не закрывает остальную часть ZIP-файла, поэтому я застрял с ним, оставив его открытым. Есть ли способ безопасно закрыть ZIP-файл и сохранить InputStream для возврата?

Ответ №1:

Вот реализация InputStream из ZipFile:

 /*
* Inner class implementing the input stream used to read a
* (possibly compressed) zip file entry.
*/
private class ZipFileInputStream extends InputStream {

   ...

   public int read(byte b[], int off, int len) throws IOException {
       if (rem == 0) {
           return -1;
       }
       if (len <= 0) {
           return 0;
       }
       if (len > rem) {
           len = (int) rem;
       }
       synchronized (ZipFile.this) {
           ensureOpenOrZipException();
  

Обратите внимание на вызов #ensureOpenOrZipException .

Итак, ответ на ваш вопрос, к сожалению, нет, нет способа сохранить поток открытым.

Вместо этого вы могли бы обернуть и подключить #close к InputStream, чтобы закрыть ваш zip-файл:

 InputStream zipInputStream = ...
return new InputStream() {
    @Override
    public int read() throws IOException {
        return zipInputStream.read();
    }
    @Override
    public void close() throws IOException {
        zipInputStream.close();
        zipFile.close();
    }
}
  

Другим подходом было бы буферизировать его:

 InputStream myZipInputStream = ...
//Read the zip input stream fully into memory
byte[] buffer = ByteStreams.toByteArray(zipInputStream);
zipFile.close();
return new ByteArrayInputStream(buffer);
  

Очевидно, что теперь все это ушло в память, поэтому ваши данные должны быть разумного размера.

Комментарии:

1. Почему это взлом? Это простая инкапсуляция zip #close . Я добавил другой подход, который был моей первой мыслью, но он использует буфер памяти, который может вам не подойти.

2. На самом деле, глядя на код, я понял, что getInputStream возвращает только InputStream, я думал, что это более конкретно. Тогда это не взлом!

3. Полиморфизм на помощь!

4. И обязательно оберните свой InputSteam с помощью BufferedInputStream . Однобайтовые вызовы #read ужасно работают с потоками ввода ZIP-файлов JDK.

5. Поскольку это библиотека, я не могу обеспечить перенос, если не сделаю это на своей стороне, но я думаю, можно с уверенностью предположить, что большинство людей будут конвертировать в BufferedInputStream . (Даже если они этого не сделают, они захотят открыть ZIP-файл, а не обычный файл).