В каком порядке я должен использовать GZIPOutputStream и BufferedOutputStream

StackOverflow https://stackoverflow.com/questions/1082320

  •  22-08-2019
  •  | 
  •  

Вопрос

Кто-нибудь может порекомендовать, должен ли я сделать что-то вроде:

os = new GzipOutputStream(new BufferedOutputStream(...));

или

os = new BufferedOutputStream(new GzipOutputStream(...));

Что более эффективно?Должен ли я вообще использовать BufferedOutputStream?

Это было полезно?

Решение

Какой порядок я должен использовать GzipOutputStream и BufferedOutputStream

Что касается потоков объектов, я обнаружил, что обертывание буферизованного потока вокруг потока gzip как для ввода, так и для вывода почти всегда значительно быстрее.Чем меньше были объекты, тем лучше это получалось.Лучше или одинаково во всех случаях, чем отсутствие буферизованного потока.

ois = new ObjectInputStream(new BufferedInputStream(new GZIPInputStream(fis)));
oos = new ObjectOutputStream(new BufferedOutputStream(new GZIPOutputStream(fos)));

Однако, для текстовых и прямых байтовых потоков я обнаружил, что это было ошибкой - поток gzip вокруг буферизованного потока был лишь немного лучше.Но лучше во всех случаях, чем без буферизации потока.

reader = new InputStreamReader(new GZIPInputStream(new BufferedInputStream(fis)));
writer = new OutputStreamWriter(new GZIPOutputStream(new BufferedOutputStream(fos)));

Я запустил каждую версию 20 раз, отключил первый запуск и усреднил остальные.Я также попробовал buffered-gzip-buffered, который был немного лучше для объектов и хуже для текста.Я вообще не играл с размерами буфера.


Для объектных потоков я протестировал 2 сериализованных объектных файла объемом 10 мегабайт.Для файла большего размера (38 мб) чтение было на 85% быстрее (0,7 против 5,6 секунды), но на самом деле немного медленнее при записи (5,9 против 5,7 секунды).Эти объекты содержали в себе несколько больших массивов, что, возможно, означало более крупные записи.

method       crc     date  time    compressed    uncompressed  ratio
defla   eb338650   May 19 16:59      14027543        38366001  63.4%

Для файла меньшего размера (18 мб) чтение было на 75% быстрее (1,6 против 6,1 секунды) и на 40% быстрее для записи (2,8 против 4,7 секунды).В нем находилось большое количество мелких предметов.

method       crc     date  time    compressed    uncompressed  ratio
defla   92c9d529   May 19 16:56       6676006        17890857  62.7%

Для чтения / записи текста я использовал текстовый файл csv размером 64 мб.Поток gzip вокруг буферизованного потока был на 11% быстрее при чтении (950 против 1070 миллисекунд) и немного быстрее при записи (7,9 против 8,1 секунды).

method       crc     date  time    compressed    uncompressed  ratio
defla   c6b72e34   May 20 09:16      22560860        63465800  64.5%

Другие советы

GZIPOutputStream - Выходной поток уже поставляется со встроенным буфером.Таким образом, нет необходимости помещать BufferedOutputStream прямо рядом с ним в цепочке.отличный ответ gojomo уже дает некоторые рекомендации о том, где разместить буфер.

Размер буфера по умолчанию для GZIPOutputStream составляет всего 512 байт, поэтому вы захотите увеличить его до 8 КБ или даже 64 КБ с помощью параметра конструктора.Размер буфера по умолчанию для BufferedOutputStream равен 8 КБ, поэтому вы можете оценить преимущество при объединении GZIPOutputStream по умолчанию и BufferedOutputStream.Это преимущество также может быть достигнуто путем правильного определения размера встроенного буфера GZIPOutputStream.

Итак, чтобы ответить на ваш вопрос: "Должен ли я вообще использовать BufferedOutputStream?" → Нет, в вашем случае вам не следует его использовать, но вместо этого установите буфер GZIPOutputStream равным не менее 8 КБ.

Буферизация помогает, когда конечное назначение данных лучше всего считывать / записывать большими порциями, чем ваш код в противном случае передал бы их.Таким образом, вы обычно хотите, чтобы буферизация была как можно ближе к месту, которому нужны большие куски.В ваших примерах это пропущенное "...", поэтому оберните BufferedOutputStream в GZIPOutputStream .И настройте размер буфера BufferedOutputStream так, чтобы он соответствовал тому, что, как показывает тестирование, лучше всего работает с местом назначения.

Я сомневаюсь, что BufferedOutputStream снаружи сильно помог бы, если вообще помог бы, без явной буферизации.Почему бы и нет?GZIPOutputStream будет выполнять свои функции записи() в "..." блоками одинакового размера, независимо от того, присутствует внешняя буферизация или нет.Таким образом, оптимизация для "..." невозможна;вы застряли с тем, каких размеров GZIPOutputStream write()s .

Обратите также внимание, что вы используете память более эффективно, буферизуя сжатые данные, а не несжатые.Если ваши данные часто подвергаются 6-кратному сжатию, "внутренний" буфер эквивалентен "внешнему" буферу в 6 раз большего размера.

Обычно вам нужен буфер , близкий к вашему FileOutputStream (предполагая , что это то , что ...представляет), чтобы избежать слишком большого количества обращений к операционной системе и частого доступа к диску.Однако, если вы записываете много небольших фрагментов в GZIPOutputStream, вам также может пригодиться буфер вокруг GZIPOS.Причина в том, что метод write в GZIPOS синхронизирован, а также приводит к нескольким другим синхронизированным вызовам и паре собственных вызовов (JNI) (для обновления CRC32 и выполнения фактического сжатия).Все это увеличивает дополнительные накладные расходы на каждый вызов.Так что в таком случае я бы сказал, что вы выиграете от обоих буферов.

Я предлагаю вам попробовать простой тест, чтобы определить, сколько времени требуется для сжатия большого файла, и посмотреть, имеет ли это большое значение.GZIPOutputStream действительно имеет буферизацию, но это буфер меньшего размера.Я бы сделал первый с буфером 64 КБ, но вы можете обнаружить, что лучше делать оба варианта.

Прочитайте javadoc, и вы обнаружите, что BIS используется для буферизации байтов, прочитанных из некоторого исходного источника.Как только вы получите необработанные байты, вы захотите сжать их, чтобы обернуть BIS с помощью GIS.Нет смысла буферизовать выходные данные из GZIP, потому что нужно подумать, как насчет буферизации GZIP, кто собирается это делать?

new GzipInputStream( new BufferedInputStream ( new FileInputXXX
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top