http://habrahabr.ru/post/196602/
Приступая к работе с Objective-Zip из песочницы tutorial
Здравствуйте, уважаемые читатели Хабра!
Наверняка многие из Вас уже имели дело со сжатием данных, программируя под iOS.
Совсем недавно передо мной возникла задача подобного рода. В приложении, над которым я работал, нужно было программно, без потерь данных, сжимать большого объема файлы. Проблема состояла в том, что на устройствах, использующих приложение, не всегда был достаточный объем оперативной памяти. Сжимая огромный файл целиком, приложение просто падало из-за нехватки памяти.
Необходимо было сжимать файл по частям.
Перебрав много разных вариантов, я остановился на очень удобном для подобных задач решении. Этим решением является использование библиотеки Objective-Zip.
Об этой маленькой, но очень удобной и функциональной библиотеке, я и хочу Вам рассказать.
Objective-Zip — это небольшая Objective-C библиотека, которая оборачивает ZLib и MiniZip в единую объектно-ориентированную сущность которая предоставляет основные функции для чтения и записи zip файлов.
Библиотека распространяется только в виде исходного кода, так что Вам необходимо просто скачать тестовое приложение и скопировать и вставить эти каталоги в собственном проекте:
Библиотека сосредоточена в классе ZipFile. Он может быть создан общей Objective-C процедурой alloc с последующей инициализацией init, с указанием в последнем случае — zip-файл будет создаваться, изменяться или распаковываться:
Операции создания и добавления имеют модификатор доступа только запись (read-only), в то время как распаковка — только чтение (write-only). Очевидно, что нельзя запрашивать операции создания/добавления при созданном только для распаковки объекте класса и наоборот.
ZipFile класс имеет несколько методов для добавления новых файлов в zip-архив. Один из методов поддерживает шифрование с помощью пароля, другой шифрование не использует. Оба метода возвращают экземплярZipWriteStream класса, который будет использоваться исключительно для записи содержимого файла, а затем должен быть закрыт:
Для начала мы должны создать объект класса ZipFile, задав ему режим распаковки. Далее мы находим первый файл и от него, до самого конца можем считывать все остальное. Считывание происходит с помощью классаZipReadStream, который тоже должен быть закрыт после использования:
Помните, что в экземпляре NSMutableData, который действует как буфер чтения, поле length должно быть установлено в значение больше, чем 0 (readDataWithBuffer API будет использовать эту длину, чтобы знать сколько байт можно вынести из архива).
Используя ZipFile класс в режиме распаковки, легко можно получить список файлов архива, заполняя NSArrayобъектами класса FileInZipInfo. Вы можете использовать его свойство name, чтобы найти файл внутри архива и распаковать его:
Помните, что класс FileInZipInfo предоставляет нам два размера:
После всего, нужно не забывать о закрытии объекта класса ZipFile. Не выполнив нижеуказанную команду, Вы рискуете повредить используемый архив, или вызвать непредвиденное поведение в Вашем проекте.
Следует отметить, что как таковой иерархии файлов/папок внутри архива нет. Эта иерархия включена в имя файла (например: файл с именем «x/y/z/file.txt»). Это зависит от программы, которая извлекает файл и рассматривает имя как структуру, восстанавливая файл в файловой системе (и наоборот во время создания архива). Общие операции упаковки/распаковки следуют этому правилу.
Если Вам нужно извлечь огромные файлы, которые не могут содержаться в памяти, Вы можете использовать циклы чтения/записи и буфер, например так:
Если вдруг, во время операции, что-то пошло не так — не беспокойтесь. Objective-Zip всегда будет генерировать исключение класса ZipException, который содержит свойство с конкретным кодом ошибки MiniZip. Зная этот код, Вы легко найдете причину ошибки.
Библиотека распространяется под лицензией New BSD License.
Наверняка многие из Вас уже имели дело со сжатием данных, программируя под 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