Предпочтительный способ использования Java ZipOutputStream и BufferedOutputStream
В Java важно ли сначала создать ZipOutputStream, или BufferedOutputStream первый? Пример:
FileOutputStream dest = new FileOutputStream(file);
ZipOutputStream zip = new ZipOutputStream(new BufferedOutputStream(dest));
// use zip output stream to write to
Или:
FileOutputStream dest = new FileOutputStream(file);
BufferedOutputStream out = new BufferedOutputStream(new ZipOutputStream(dest));
// use buffered stream to write to
В моих ненаучных таймингах я, похоже, не очень разбираюсь в различиях. Я не вижу ничего в Java API, который говорит, что один из этих способов является необходимым или предпочтительным. Любой совет? Похоже, что сначала сжимает вывод, а затем буферизирует его для записи, будет более эффективным.
Ответы
Ответ 1
Вы всегда должны обернуть BufferedOutputStream
с помощью ZipOutputStream
, а не наоборот. См. Приведенный ниже код:
FileOutputStream fos = new FileOutputStream("hello-world.zip");
BufferedOutputStream bos = new BufferedOutputStream(fos);
ZipOutputStream zos = new ZipOutputStream(bos);
try {
for (int i = 0; i < 10; i++) {
// not available on BufferedOutputStream
zos.putNextEntry(new ZipEntry("hello-world." + i + ".txt"));
zos.write("Hello World!".getBytes());
// not available on BufferedOutputStream
zos.closeEntry();
}
}
finally {
zos.close();
}
Как говорится в комментариях, методы putNextEntry()
и closeEntry()
недоступны в BufferedOutputStream
. Без вызова этих методов ZipOutputStream
генерирует исключение java.util.zip.ZipException: no current ZIP entry
.
Для полноты, стоит отметить, что предложение finally вызывает только close()
на ZipOutputStream
. Это связано с тем, что по соглашению все встроенные средства оболочки потока вывода Java распространяют закрытие.
ИЗМЕНИТЬ
Я просто тестировал это наоборот. Оказывается, что обертка ZipOutputStream
с BufferedOutputStream
, а затем только вызов write()
на нем (без создания/закрытия записей) не будет бросать ZipException
. Вместо этого полученный ZIP файл будет поврежден, без каких-либо записей внутри него.
Ответ 2
Вы должны:
ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(dest));
потому что вы хотите буферизировать запись на диск (потому что это намного эффективнее в больших блоках данных, чем во многих маленьких).
Это
new BufferedOutputStream(new ZipOutputStream(dest));
будет буферизовать перед сжатием zip. Но все это происходит в памяти и не нуждается в буферизации, потому что много небольших обращений к памяти примерно одинаковой скорости, чем несколько больших.
В общем объеме памяти необходимое время пропорционально количеству байтов чтения/записи.
Как упоминалось в комментариях:
Методы ZipOutputStream
, которые не являются частью BufferedOutputStream
, также недоступны. Например. putNextEntry
и closeEntry
.