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

в 12:07, , рубрики: iOS, objective-c, zip, архивация, Программирование, разработка под iOS, сжатие, метки: , , , , ,

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

Наверняка многие из Вас уже имели дело со сжатием данных, программируя под 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.
Это те основные моменты, с которыми я хотел Вас, уважаемый читатель, познакомить.
Искренне надеюсь, что эта статья была полезной для Вас.
Успехов!

Автор: NahashSVB

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js