Wednesday, November 27, 2013

Приступая к работе с Objective-Zip http://habrahabr.ru/post/196602/

http://habrahabr.ru/post/196602/

Приступая к работе с Objective-Zip из песочницы tutorial

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

Наверняка многие из Вас уже имели дело со сжатием данных, программируя под 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.

No comments:

Post a Comment