Почему deflate делает мои данные БОЛЬШЕ?

Я хотел сжать некоторые данные, поэтому решил запустить поток с помощью deflate.

Он увеличился с 304 байт до 578. Это в 1,9 раза больше. Я пытался его сжать..... Что я здесь делаю не так?

using (MemoryStream ms2 = new MemoryStream())
using (var ms = new DeflateStream(ms2, CompressionMode.Compress, true))
{
    ms.WriteByte(1);
    ms.WriteShort((short)txtbuf.Length);
    ms.Write(txtbuf, 0, txtbuf.Length);
    ms.WriteShort((short)buf2.Length);
    ms.Write(buf2, 0, buf2.Length);
    ms.WriteShort((short)buf3.Length);
    ms.Write(buf3, 0, buf3.Length);
    ms.Flush();
    result_buf = ms2.ToArray();
}

person Community    schedule 14.07.2012    source источник
comment
Что произойдет, если вы поместите свои данные в файл и заархивируете его?   -  person Greg Hewgill    schedule 14.07.2012
comment
@GregHewgill zip дает мне 465, gz дает мне 349, оригинал 319. (я не знаю, что я изменил, но данные создаются случайным образом при каждом запуске). Я не могу сказать, что пытается сделать .NET deflate, поскольку я сделал поток потоком ввода-вывода. Мне пришлось бы написать больше кода, чтобы проверить данные в этом прогоне.   -  person    schedule 14.07.2012
comment
204 байта — это меньше, чем один сетевой пакет, это также меньше, чем один сектор диска (и гораздо меньше, чем один на самых новых — 4k-секторных — дисках). Накладные расходы на сжатие таких небольших объемов данных будут подавлять любую экономию за счет размера, которого обычно не бывает (даже если вы не сталкивались с этой проблемой).   -  person Richard    schedule 14.07.2012
comment
@ Ричард, это быстрый тест. Мой txtbuf будет длиннее. Однако принятый ответ прекрасно объясняет ситуацию   -  person    schedule 14.07.2012


Ответы (6)


Степень расширения ваших данных является ошибкой в классе DeflateStream. Ошибка также существует в классе GZipStream. См. мое описание этой проблемы здесь: Почему мой C# gzip создает файл большего размера, чем Fiddler или PHP?.

Не используйте класс DeflateStream, предоставленный Microsoft. Вместо этого используйте DotNetZip, который предоставляет замещающие классы.

Несжимаемые данные немного расширятся при попытке их сжатия, но только на небольшую величину. Максимальное расширение от правильно написанного компрессора deflate составляет пять байтов плюс небольшая доля процента. Расширение несжимаемых данных zlib (с настройками по умолчанию для необработанного дефляции) составляет 5 байт + 0,03% входных данных. размер. Ваши 304 байта, если они несжимаемые, должны выйти как 309 байтов из компрессора необработанного дефляции, такого как DeflateStream. Расширение с коэффициентом 1,9 для чего-то большего, чем пять или шесть байтов, является ошибкой.

person Mark Adler    schedule 14.07.2012

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

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

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

person Wulfram    schedule 14.07.2012
comment
Это определенно будет иметь место, также обратите внимание, что это зависит от размера потока, меньшие потоки гораздо труднее сжимать, чтобы получить преимущества из-за того, что соотношение накладных расходов: размер данных намного выше. - person Aaron Murgatroyd; 14.07.2012
comment
Это хороший момент. Думаю, я должен также упомянуть, что многие данные уже сжаты по своей природе, например, изображения/видео/аудиофайлы или зашифрованные файлы. Когда вы пытаетесь сжать эти типы данных, часто все становится хуже. - person Wulfram; 14.07.2012

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

Вы не делаете ничего плохого.

person Patrick Hughes    schedule 14.07.2012

Разве это не должно быть

using (var ms = new DeflateStream(ms2, CompressionMode.Compress, true))

вместо

using (var ms = new DeflateStream(ms, CompressionMode.Compress, true))

Если вы хотите украсить свой MemoryStream с помощью DeflateStream, это должно быть примерно так.

person darkey    schedule 14.07.2012
comment
ой, ваше право. Это была опечатка. С# выдает ошибку компиляции, если я ошибаюсь - person ; 14.07.2012

Вы сами ответили на свой вопрос в своем комментарии:

я не знаю, что я изменил, но данные создаются случайным образом при каждом запуске

Случайные данные сложно сжимать. В общем, когда данные содержат множество шаблонов (например, текст из словаря или веб-сайта), они хорошо сжимаются. Но худший случай для алгоритма сжатия — это когда вы сталкиваетесь со случайными данными. В истинно случайных данных нет закономерностей; как тогда алгоритм сжатия может ожидать, что сможет сжать его?

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

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

person Mike Bailey    schedule 14.07.2012
comment
Неправда, ну, частично. Только одна часть того, что я сжал, является случайной (время + немного других случайных байтов, таких как байты), и есть много текста ascii и base64, который должен быть сжимаемым;). На самом деле это реализация .NET. Это отстой. Использование deflate для html-файла дает мне 26%, а моно — 5% от исходного файла. - person ; 14.07.2012
comment
Нет, он не ответил на свой вопрос. Нет причин для увеличения настолько данных. Это оказывается ошибкой, любезно предоставленной Microsoft. Смотрите мой ответ. - person Mark Adler; 14.07.2012

У меня нет репутации, чтобы оставлять комментарии, однако причина, по которой производительность сжатия хуже, чем вы ожидаете, не связана с ошибкой как таковой, а, по-видимому, с патентом:

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

и

Что ж, объяснение, которое я получил (от кого-то из MS), когда я спросил то же самое, заключалось в том, что это было связано с тем, что Microsoft не могла использовать алгоритм GZip без его модификации; из-за проблем с патентами/лицензиями.

http://social.msdn.microsoft.com/Forums/fr-FR/c5f0b53c-a2d5-4407-b43b-9da8d39c01df/why-do-gzipstream-compression-ratio-so-bad?forum=netfxbcl

Первоначально я подозревал реализацию gzip от Microsoft; Я знал, что они внедрили алгоритм Deflate, который не самый эффективный, но не имеет патентов.

http://challenge-me.ws/post/2010/11/05/Do-Not-Take-Microsofts-Code-for-Granted.aspx

person Matthew1471    schedule 06.07.2014