Приступая к работе с Objective-Zip

от автора

Здравствуйте, уважаемые читатели Хабра!

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

Перебрав много разных вариантов, я остановился на очень удобном для подобных задач решении. Этим решением является использование библиотеки Objective-Zip.

Об этой маленькой, но очень удобной и функциональной библиотеке, я и хочу Вам рассказать.

Objective-Zip — это небольшая Objective-C библиотека, которая оборачивает ZLib и MiniZip в единую объектно-ориентированную сущность которая предоставляет основные функции для чтения и записи zip файлов.

Добавление Objective-Zip в Ваш проект

Библиотека распространяется только в виде исходного кода, так что Вам необходимо просто скачать тестовое приложение и скопировать и вставить эти каталоги в собственном проекте:

  • ARCHelper;
  • ZLib;
  • MiniZip;
  • Objective-Zip.

Основные понятия

Библиотека сосредоточена в классе ZipFile. Он может быть создан общей Objective-C процедурой alloc с последующей инициализацией init, с указанием в последнем случае — zip-файл будет создаваться, изменяться или распаковываться:

ZipFile *zipFile= [[ZipFile alloc] initWithFileName:@"test.zip"     mode:ZipFileModeCreate]; 

Операции создания и добавления имеют модификатор доступа только запись (read-only), в то время как распаковка — только чтение (write-only). Очевидно, что нельзя запрашивать операции создания/добавления при созданном только для распаковки объекте класса и наоборот.

Добавление файла в архив

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

ZipWriteStream *stream= [zipFile writeFileInZipWithName:@"abc.txt"     compressionLevel:ZipCompressionLevelBest];  [stream writeData:abcData]; [stream finishedWriting]; 

Чтение файла из архива

Для начала мы должны создать объект класса ZipFile, задав ему режим распаковки. Далее мы находим первый файл и от него, до самого конца можем считывать все остальное. Считывание происходит с помощью класса ZipReadStream, который тоже должен быть закрыт после использования:

ZipFile *unzipFile= [[ZipFile alloc] initWithFileName:@"test.zip"     mode:ZipFileModeUnzip];  [unzipFile goToFirstFileInZip];  ZipReadStream *read= [unzipFile readCurrentFileInZip]; NSMutableData *data= [[NSMutableData alloc] initWithLength:256]; int bytesRead= [read readDataWithBuffer:data];  [read finishedReading]; 

Помните, что в экземпляре NSMutableData, который действует как буфер чтения, поле length должно быть установлено в значение больше, чем 0 (readDataWithBuffer API будет использовать эту длину, чтобы знать сколько байт можно вынести из архива).

Просмотр файлов в архиве

Используя ZipFile класс в режиме распаковки, легко можно получить список файлов архива, заполняя NSArray объектами класса FileInZipInfo. Вы можете использовать его свойство name, чтобы найти файл внутри архива и распаковать его:

ZipFile *unzipFile= [[ZipFile alloc] initWithFileName:@"test.zip"     mode:ZipFileModeUnzip];  NSArray *infos= [unzipFile listFileInZipInfos]; for (FileInZipInfo *info in infos) {     NSLog(@"- %@ %@ %d (%d)", info.name, info.date, info.size,         info.level);      // Locate the file in the zip     [unzipFile locateFileInZip:info.name];      // Expand the file in memory     ZipReadStream *read= [unzipFile readCurrentFileInZip];     NSMutableData *data= [[NSMutableData alloc] initWithLength:256];     int bytesRead= [read readDataWithBuffer:data];     [read finishedReading]; } 

Помните, что класс FileInZipInfo предоставляет нам два размера:

  • length — размер оригинального файла (не сжатого);
  • size — размер сжатого файла.

Завершение работы с архивом

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

[zipFile close]; 

Иерархия файлов/папок внутри архива

Следует отметить, что как таковой иерархии файлов/папок внутри архива нет. Эта иерархия включена в имя файла (например: файл с именем «x/y/z/file.txt»). Это зависит от программы, которая извлекает файл и рассматривает имя как структуру, восстанавливая файл в файловой системе (и наоборот во время создания архива). Общие операции упаковки/распаковки следуют этому правилу.

Управление памятью

Если Вам нужно извлечь огромные файлы, которые не могут содержаться в памяти, Вы можете использовать циклы чтения/записи и буфер, например так:

NSFileHandle *file= [NSFileHandle fileHandleForWritingAtPath:filePath]; NSMutableData *buffer= [[NSMutableData alloc]     initWithLength:BUFFER_SIZE];  ZipReadStream *read= [unzipFile readCurrentFileInZip];  // Read-then-write buffered loop do {      // Reset buffer length     [buffer setLength:BUFFER_SIZE];      // Expand next chunk of bytes     int bytesRead= [read readDataWithBuffer:buffer];     if (bytesRead > 0) {          // Write what we have read         [buffer setLength:bytesRead];         [file writeData:buffer];      } else         break;  } while (YES);  // Clean up [file closeFile]; [read finishedReading]; [buffer release]; 

Обработка исключений

Если вдруг, во время операции, что-то пошло не так — не беспокойтесь. Objective-Zip всегда будет генерировать исключение класса ZipException, который содержит свойство с конкретным кодом ошибки MiniZip. Зная этот код, Вы легко найдете причину ошибки.

Лицензия

Библиотека распространяется под лицензией New BSD License.

P.S.
Это те основные моменты, с которыми я хотел Вас, уважаемый читатель, познакомить.
Искренне надеюсь, что эта статья была полезной для Вас.
Успехов!

ссылка на оригинал статьи http://habrahabr.ru/post/196602/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *