. Создаем свой архиватор в 200 строчек кода
Создаем свой архиватор в 200 строчек кода

Создаем свой архиватор в 200 строчек кода

Архивы в современное время играют немаловажную роль в хранении данных. Они позволяют хранить внутри себя набор разнообразных файлов. Это достаточно удобно, например, для передачи данных по сети — легче передавать один файл, чем несколько. Также архивы позволяют хранить информацию в удобной структурированной форме. Вы это, несомненно, осознавали и до этого.

В данной статье мы попробуем разработать собственный кроссплатформенный консольный архиватор с поддержкой как архивации, так и распаковки ранее запакованых файлов. Требуется уложиться в 200 строчек кода. Писать будем на C++, используя при этом лишь его стандартные библиотеки. Поэтому привязанности к определенной платформе нет — работать это будет и в Windows, и в Linux. Почему C++, а не привычный C? Не то, что бы я имею что-то против СИ, просто в нем достаточно проблематично работать со строками и, к тому же, отсутствует ООП. Следовательно, если бы мы использовали C, то в 200 строк, думаю, вряд ли бы уложились. Ну, да ладно, приступим же!

Intro

Для начала немного теории. Думаю, все, кто читает эту статью, прекрасно знают, что любой файл — это обыкновенная последовательность байт, которой оперирует процесс, открывший файл( ресурс ). Файлы — это последовательность байт, которая приобретает различные формы в пределах файловой системы. Формы — это типы файлов, их назначения. Для операционной системы файлы — это байты, о назначении которых ей ничего не известно. Стандартные потоки вывода также манипулируют последовательностью байт, попутно модифицируя их( это зависит от класса потока, некоторые потоки являются «сырыми», т.е работают, непосредственно, с байтами ).

Так что же требуется знать, чтобы написать архиватор? Думаю, кроме наличия некоторых знаний уровня «выше базового», касающихся C++, лишь то, что файл — это байты. И ничего более.

Codding

Пусть наш консольный архиватор будет называться Zipper`ом. Мне кажется, вполне подходящее название :)

Для работы потребуется несколько стандартных библиотек C++:

Да, мы будем также использовать STL. Это удобно, «модно» и лаконично. STL позволит нам в разы сократить код. Также мы будем использовать стандартное пространство имен:

Теперь разберемся с тем, как вообще будет функционировать наш архиватор. Итак, Zipper будет принимать из консоли некоторые параметры:

-pack — архивация(упаковка) файлов -unpack — разархивация(распаковка) данных из файла-архива -files — набор файлов для архивации( при наличии -pack ) или один файл для разархивации( при наличии -unpack ) -path — путь для сохранения разархивированных данных( при наличии -unpack ) или путь для сохранения архива ( при наличии -pack )

Распаковка данных из архива тесно связана с тем, что происходит при архивации. Архивация же будет происходить в два этапа:

1) Получение информации об архивируемых файлах 2) Создание единого файла архива, содержащего блок информации о всех файлах внутри себя и все файлы в бинарном представлении.

При архивации сначала будет происходить получении информации о всех файлах и сохраняться в промежуточный текстовый файл в таком виде:

Затем текстовый файл побайтно будет переписан в начало файла-архива и удален. Пояснения к параметрам формата информации:

size_of_string — пять байт, содержащие числа, составляющие единое число в 10-ичной системе счисления, которое указывает общий размер(в байтах) последующего блока информации( до <end_of_info> )

filesize — размер определенного файла в байтах filename — имя этого файла.

Ну а после блока с информацией мы просто переписываем все архивируемые файлы побайтно в наш архив. Вот, собственно, и весь процесс архивации. Теперь вернемся к коду.

Для наибольшего удобства мы создадим один класс «Zipper», который будет отвечать за все, что происходит внутри архиватора. Итак, архитектура класса " Zipper ":

Нам также потребуется кое-какой простой «метод-отшельник» для подсчета количества разрядов в числе. Это потребуется, например, для записи числа в архив, как динамического буфера символов. Метод:

Итак, мы уже имеем более-менее качественный интерфейс. Но пока все то, что было задумано, лишь в сознании. Пора бы воплотить идею :) Реализуем метод архивации данных:

Осталось лишь реализовать наш заветный метод для получения информации. Метод " getInfo() ":

На этом с архивацией данных все. Осталось лишь добавить смысла в архивацию, а именно — распаковку того, что внутри архива. Для этого реализуем последний нереализованный метод класса Zipper — метод OutCompress(). Как говорилось в начале статьи, распаковка тесно связана с упаковкой.Эта привязанность связана с информационным блоком. Если возникнет ошибка при архивации, а именно на этапе получения информации( например, где-то просчет на 1 байт ), то весь процесс распаковки с треском рухнет. Но, этого нам, конечно же, не нужно! Мы ведь пишем валидный код. Итак, процесс распаковки состоит всего из одного этапа, содержащего два подэтапа:

1) Разборка блока с информацией о том, что содержится в архиве 2) Чтение «мессива» байт всех файлов внутри архива по правилам, указанным в информационной секции.

Что ж, реализация метода распаковки:

Вот, собственно, и все, что касается нашего архиватора/распаковщика. Но так как это приложение планируется использовать в консольном режиме, то нам придется подстроить наш Zipper для консоли. Нам необходимо реализовать поддержку 4 параметров, речь о которых шла в самом начале. Это делается довольно легко:

Вот, собственно, и все приложение.

Testing

Теперь займемся неотъемлемой частью разработки — тестированием. Для наибольшего удобства я все продемонстрирую в картинках.

1) В корне локального диска «C» я создам папку с именем «test», в которой будут находиться все файлы для архивации. В «C:test» создам еще одну папку для демонстрации разархивации — «unpack»:

Далее открываем консоль и архивируем содержимое " C:test ":

Смотрим, что новенького в " C:test ":

Видим там наш архив — «binary.zipper». Откроем его с помощью какого-нибудь текстового редактора для изучения содержимого. Я это сделаю с помощью NotePad++:

Мы видим секцию с информацией и последующим мессивом байт всех файлов. Что ж, класс =)

Распакуем архив в " C:testunpack ":

Смотрим, что получилось на выходе, в " C:testunpack ":

Как можем наблюдать, все в целости и сохранности. Ну что ж, архиватор отлично работает. Причем мы уложились в 200 строчек кода — в общем счете 190 строчек.

Outro

Как вы убедились, написать свой архиватор достаточно просто даже с базовыми знаниями C++, STL и ООП в целом. Последнее даже, скорее, лишнее, так как вполне можно обойтись без целевого класса Zipper. В таком случае код сократится еще на 15-25 строчек :)

Для тех, кому интересно посмотреть на весь код целиком, прошу перейти вот сюда.

📎📎📎📎📎📎📎📎📎📎