Основные форматы упаковки данных
Дата добавления: 2015-08-31 ; просмотров: 1907 ; Нарушение авторских прав
В настоящее время применяется несколько десятков программ-архиваторов, которые отличаются перечнем функций и параметрами работы, однако лучшие из них имеют примерно одинаковые характеристики. Из числа наиболее известных программ можно выделить ARJ, РКРАК, LHA, ICE, HYPER, CAB, ZIP, РАК, ZOO, EXPAND, RAR.
Существует еще один интересный класс программ, которые также можно отнести к архиваторам. Это упаковщики исполняемых файлов (т.е. файлов с расширением .com и .ехе). После упаковки исполняемые файлы остаются работоспособными, и их можно запустить без каких-либо дополнительных операций. Степень сжатия достигает 10-50%. В последнее время производители программных продуктов по возможности сами упаковывают исполняемые файлы. Кроме того, имеется целый класс программ (часто называемых утилитами уплотнения или сжатия диска), упаковывающих файлы «на лету», в момент записи на диск, и распаковывающих их в процессе чтения. Эти программы прозрачны для пользователя, и при работе с ОС никаких видимых изменений не происходит (за исключением незначительного увеличения времени, затрачиваемого на дисковые операции), но и выигрыш оставляет желать лучшего (реально не более 40% объема). Типичный пример программы сжатия диска — утилита DriveSpace, входящая в состав операционной системы Windows 95/98.
Среди всего множества различных форматов упаковки можно выделить наиболее часто встречающиеся форматы .ZIP, .ARJ и .RAR.
Формат .ZIP. Это один из ранних форматов архивации. В MS-DOS для работы с этим форматом используются две программы: PKZIP.EXE для упаковки файлов и PKUNZIP.EXE для их распаковки. В ОС семейства Windows обе функции выполняет одна программа — WinZip. Несмотря на свою «древность», этот формат сегодня используется чрезвычайно широко. Это связано с тем, что это основной формат, в котором поставляются программы и драйверы из Интернета.
Формат .ARJ. Самый популярный формат первой половины 90-х годов. И упаковка, и распаковка производятся одной программой ARJ.EXE. По степени сжатия ощутимо превосходит формат .ZIP, но с появлением Windows 95 этот формат заметно отступил на второй план и остался популярным форматом сжатия для MS-DOS. Это связано с тем, что при сжатии файлов портятся «длинные» имена файлов. В WinArj этот недостаток устранен.
Формат .RAR. Программа WinRAR российского программиста Евгения Рошаля по потребительским свойствам объективно превосходит все остальные архиваторы. В международном секторе Интернета этот формат используют профессионалы. Поскольку WinRAR позволяет работать также с архивами в форматах .ZIP, .ARJ и некоторых других, он в общем-то удовлетворяет большинство потребностей пользователя в средствах сжатия и разуплотнения информации.
Источник
Упаковка и распаковка в .NET
Мы уже знаем особенности работы с памятью и доступные структуры данных в .NET приложениях, в этом посте мы разберем упаковку и распаковку, а также рассмотрим, как эти две операции влияют на производительность приложения.
Что такое упаковка и распаковка?
Зачем нам задумываться об упаковке и распаковке? Разве это не обязанность .NET-среды, которая следит за управлением данных и, соответственно, сама «выбирает» наиболее оптимальный способ их хранения?
На самом деле — нет. Что очень важно знать и понимать — так это механизм перемещения данных из области стека в кучу — и наоборот.
Помните:
- Когда любой значимый тип присваивается к ссылочному типу данных, значение перемещается из области стека в кучу. Эта операция называется упаковкой.
- Когда любой ссылочный тип присваивается к значимому типу данных, значение перемещается из области кучи в стек. Это называется распаковкой.
К примеру, здесь мы имеем следующий пример упаковки:
А вот состояние памяти в момент произведения операции:
Чтобы сохранить значение «123» в виде объекта, в куче создается «упаковка», куда впоследствии и перемещаются данные.
Когда же производится распаковка:
Вот что происходит с памятью:
Значение «123» было изъято из упаковки и помещено назад в область стека.
Заметьте, что когда тип данных i упаковывается внутри объекта o, в стеке хранится лишь ссылка, в то время как само значение хранится в куче. Как только производиться распаковка, данные в куче обязаны быть скопированы в стек (переменная j). В обоих случаях наша цель — это работать с тем самым значением (123).
Как вы можете себе представить, сии операции могут быть достаточно ресурсоемкими.
Тема связана со специальностями:
Давайте рассмотрим IL
Когда мы производим подобный анализ производительности, часто бывает полезно заглянуть непосредственно в Intermediate Language (IL).
Мы еще не рассматривали эту концепцию, но, как вы наверняка знаете, когда мы производим компиляцию в DLL или EXE, выходной файл на самом деле содержит IL — промежуточный код, который в последствии исполняется JIT и впоследствии — виртуальной машиной. Среда выполнения .NET обязана как-то знать, нужно ли упаковывать или распаковывать определенные переменные. Поэтому для обозначения этих операций также требуются дополнительные затраты памяти.
Давайте создадим несложное .NET консольное приложение:
Теперь скомпилируем приложение и при помощи утилитки ILSpy посмотрим его код внутри EXE.
Как только EXE-файл будет открыт в ILSpy, пронавигируемся к методу Main, выбрав «IL with C#».
Заметьте, что операция box выполняется только после присвоение ссылочному типу значения значимого. И наоборот: unbox.any — только после попытки присвоить ссылочному типу данных значимой переменной.
Это де-факто способ, которым операции упаковки и распаковки представлены в IL.
Когда стоит производить упаковку и распаковку?
Код в примере выше скорее всего вам покажется наивным, и вы можете подумать: «Эй, что за вздор! Я никогда не буду такого делать». Что же, в большинстве случаев это действительно так. Но данные в нашем приложении часто упаковываются и распаковываются, когда мы об этом даже не догадываемся.
Гетерогенные коллекции
К примеру, старая школа до сих пор может похвастаться ArrayList.
Метод добавления элемента здесь, как можно отметить, принимает object-параметр.
Таким образом, и здесь производится наша излюбленная упаковка.
Впрочем, подобное кануло в лету с приходом обобщений и обобщенных коллекций.
Конкатенация строк
Другой интересный пример в виде конкатенации строк.
Эта операция требует наличия метода String.Concat, который принимает два object-параметра.
Видео курсы по схожей тематике:
C# Базовый (ООП) 2021
How to C# Углубленный
Дабы избежать подобных ситуаций, нам достаточно просто немного изменить код, используя на переменной типа int метод ToString (и здесь стоит проигнорировать сообщение ReSharper о том, что операция бессмысленна:) ).
И все! Никакой упаковки больше нет.
Вообще, это далеко не единичные примеры для демонстрации. Но цель нашей статьи — донести четкое представление о том, что такое упаковка и распаковка и когда они применяются.
Производительность
Как мы уже говорили, упаковка и распаковка требуют определенных затрат производительности. В случае с конкатенацией строк, выигрыш от применения ToString весьма незначителен. Именно потому, как я упомянул выше, даже ReSharper не советовал нам делать подобное:
В этом случае гораздо лучше сохранить читабельность кода без ToString.
Целесообразность оптимизации появляется, как правило, тогда, когда операции упаковки и распаковки предстоит производить в цикле сотни и тысячи раз. В этом случае время выполнения кода с упаковкой может составлять порядка 150 процентов от времени исполнения кода без нее (вы можете сами создать тестовое приложение и сравнить требуемый промежуток времени).
Упакованные значения могут также требовать больше памяти, чем значения в стеке. Копирование значений в/из стека также требует своих затрат. Согласно MSDN, упаковка может занимать порядка 20 раз больше времени, нежели простое присвоение. В то время как распаковка примерно в 4 раза медленней простого присвоения.
Итак. зачем же тогда вообще нужно использовать упаковку и распаковку?
Несмотря на все недостатки в плане падения производительности .NET -приложения, концепции упаковки и распаковки были внедрены в .NET не просто так. И вот причины:
- .NET-стандарт обладает общей системой типов, что позволяет представлять и ссылочные. и значимые типы схожим образом — и все это благодаря упаковке.
- Коллекции можно было использовать для хранения значимых типов до появления обобщений.
- Упрощения кода, вроде конкатенации строк и так далее.
Упаковка и распаковка настолько распространены, что мы не может избежать их полностью. Мы должны знать принцип их работы, чтобы минимизировать их использование, но к этому нужно подходить разумно. Не тратьте свое время на постоянную оптимизацию кода, частую проверку через IL, чтобы убедиться, дабы ни одна лишняя операция упаковки не была использована. Помните, что чистота и простота чтения кода иногда значительно более важна, нежели незаметное, мельчайшее ускорение работы программы.
Бесплатные вебинары по схожей тематике:
Типичные ошибки в коде на примере С++, С# и Java
Как стать C# /.NET разработчиком?
Шахматный клиент-сервер на C#. Часть 1. Алгоритм. Программирование шахматных правил игры.
Подведем итоги
В сегодняшнем уроке мы рассмотрели, что такое упаковка и распаковка, как она представлена в IL-коде, и какое влияние на производительность они имеют. Искренне надеюсь, моя статья сумела прояснить некоторые общие концепции, хотя бы чуть-чуть. 🙂
В грядущих статьях мы рассмотрим механизм сборки мусора. Если у вас есть идеи или пожелания касательно материала новых статьей — милости просим в комментарии!
Источник
Упаковка-преобразование и распаковка-преобразование (Руководство по программированию на C#)
Упаковка представляет собой процесс преобразования типа значения в тип object или в любой другой тип интерфейса, реализуемый этим типом значения. Когда тип значения упаковывается общеязыковой средой выполнения (CLR), он инкапсулирует значение внутри экземпляра System.Object и сохраняет его в управляемой куче. Операция распаковки извлекает тип значения из объекта. Упаковка является неявной; распаковка является явной. Понятия упаковки и распаковки лежат в основе единой системы типов C#, в которой значение любого типа можно рассматривать как объект.
В следующем примере выполнена операция i упаковки целочисленной переменной, которая присвоена объекту o .
Затем можно выполнить операцию распаковки объекта o и присвоить его целочисленной переменной i :
Следующий пример иллюстрирует использование упаковки в C#.
Производительность
По сравнению с простыми операциями присваивания операции упаковки и распаковки являются весьма затратными процессами с точки зрения вычислений. При выполнении упаковки типа значения необходимо создать и разместить новый объект. Объем вычислений при выполнении операции распаковки, хотя и в меньшей степени, но тоже весьма значителен. Дополнительные сведения см. в разделе Производительность.
Упаковка
Упаковка используется для хранения типов значений в куче со сбором мусора. Упаковка представляет собой неявное преобразование типа значения в тип object или в любой другой тип интерфейса, реализуемый этим типом значения. При упаковке типа значения в куче выделяется экземпляр объекта и выполняется копирование значения в этот новый объект.
Рассмотрим следующее объявление переменной типа значения.
Следующий оператор неявно применяет операцию упаковки к переменной i .
Результат этого оператора создает ссылку на объект o в стеке, которая ссылается на значение типа int в куче. Это значение является копией значения типа значения, присвоенного переменной i . Разница между этими двумя переменными, i и o , показана на рисунке упаковки-преобразования ниже:
Можно также выполнять упаковку явным образом, как в следующем примере, однако явная упаковка не является обязательной.
Пример
В этом примере целочисленная переменная i преобразуется в объект o при помощи упаковки. Затем значение, хранимое переменной i , меняется с 123 на 456 . В примере показано, что исходный тип значения и упакованный объект используют отдельные ячейки памяти, а значит могут хранить разные значения.
Распаковка
Распаковка является явным преобразованием из типа object в тип значения или из типа интерфейса в тип значения, реализующего этот интерфейс. Операция распаковки состоит из следующих действий:
проверка экземпляра объекта на то, что он является упакованным значением заданного типа значения;
копирование значения из экземпляра в переменную типа значения.
В следующем коде показаны операции по упаковке и распаковке.
На рисунке ниже представлен результат выполнения этого кода.
Для успешной распаковки типов значений во время выполнения необходимо, чтобы экземпляр, который распаковывается, был ссылкой на объект, предварительно созданный с помощью упаковки экземпляра этого типа значения. Попытка распаковать null создает исключение NullReferenceException. Попытка распаковать ссылку на несовместимый тип значения создает исключение InvalidCastException.
Пример
В следующем примере показан случай недопустимой распаковки, в результате чего создается исключение InvalidCastException . В случае использования try и catch при возникновении ошибки выводится сообщение.
При выполнении этой программы выводится следующий результат:
Specified cast is not valid. Error: Incorrect unboxing.
При изменении оператора:
будет выполнено преобразование со следующим результатом:
Спецификация языка C#
Дополнительные сведения см. в спецификации языка C#. Спецификация языка является предписывающим источником информации о синтаксисе и использовании языка C#.
Источник