#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-файл, а не обычный файл).