Работа с ZIP-архивами в Swift (iOS/macOS)
Сжатие и распаковка данных — одна из ключевых задач при разработке приложений под iOS и macOS. ZIP-формат остаётся самым популярным способом упаковки файлов благодаря универсальности и встроенной поддержке в операционных системах Apple. В этой статье мы рассмотрим два основных подхода к работе с ZIP-архивами в Swift: использование встроенного фреймворка Foundation и мощной сторонней библиотеки Zip Foundation.
1. Встроенные средства Foundation (NSFileCoordinator + libz)
Начиная с iOS 9 и macOS 10.11, Apple предоставляет ограниченную, но достаточную для базовых задач поддержку ZIP через класс NSFileCoordinator и системную библиотеку libz. Однако этот способ требует ручного управления потоками и не подходит для сложных сценариев.
Пример: распаковка ZIP-архива с помощью libz
import Foundation
import Compression
func unzipFile(at sourceURL: URL, to destinationURL: URL) throws {
let sourceData = try Data(contentsOf: sourceURL)
// Используем системный декомпрессор
let decodedData = try sourceData.withUnsafeBytes { (ptr: UnsafeRawBufferPointer) -> Data in
let sourcePtr = ptr.baseAddress!.assumingMemoryBound(to: UInt8.self)
let sourceSize = sourceData.count
// Буфер для распакованных данных (обычно больше исходного)
let bufferSize = sourceSize * 4
var buffer = Data(count: bufferSize)
let decodedSize = buffer.withUnsafeMutableBytes { (destPtr: UnsafeMutableRawBufferPointer) -> Int in
let dest = destPtr.baseAddress!.assumingMemoryBound(to: UInt8.self)
return compression_decode_buffer(dest, bufferSize, sourcePtr, sourceSize, nil, COMPRESSION_ZLIB)
}
return buffer.prefix(decodedSize)
}
// Сохраняем распакованные данные
try decodedData.write(to: destinationURL, options: .atomic)
}
Ограничения встроенного подхода:
- Нет поддержки многофайловых архивов
- Отсутствует работа с паролями
- Требуется ручное управление буферами
- Сложно обрабатывать большие файлы
2. Библиотека Zip Foundation (рекомендуемый способ)
Zip Foundation — это open-source библиотека, которая предоставляет простой и элегантный API для работы с ZIP-архивами в Swift. Она поддерживает:
- Создание и распаковку архивов
- Работу с паролями (AES-256)
- Прогресс-бары через Combine или замыкания
- Потоковую обработку больших файлов
- Поддержку macOS, iOS, watchOS и tvOS
Установка через Swift Package Manager
// В файле Package.swift или через Xcode:
dependencies: [
.package(url: "https://github.com/marmelroy/Zip.git", from: "2.1.0")
]
Пример: создание ZIP-архива
import Zip
func createZipArchive() {
let fileManager = FileManager.default
let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first!
// Собираем файлы для архивации
let file1 = documentsURL.appendingPathComponent("report.pdf")
let file2 = documentsURL.appendingPathComponent("photo.jpg")
let filesToZip = [file1, file2]
// Путь к будущему архиву
let archiveURL = documentsURL.appendingPathComponent("backup.zip")
do {
// Прогресс через замыкание
try Zip.zipFiles(paths: filesToZip, zipFilePath: archiveURL, password: nil, progress: { (progress) in
print("Прогресс архивации: \(Int(progress * 100))%")
})
print("Архив создан: \(archiveURL.path)")
} catch {
print("Ошибка создания архива: \(error.localizedDescription)")
}
}
Пример: распаковка архива с паролем
import Zip
func unzipProtectedArchive() {
let fileManager = FileManager.default
let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first!
let archiveURL = documentsURL.appendingPathComponent("secure_backup.zip")
let destinationURL = documentsURL.appendingPathComponent("UnzippedFiles")
do {
// Создаём папку назначения
try fileManager.createDirectory(at: destinationURL, withIntermediateDirectories: true)
// Распаковка с паролем
try Zip.unzipFile(archiveURL, destination: destinationURL, overwrite: true, password: "secret123", progress: { (progress) in
DispatchQueue.main.async {
print("Распаковано: \(Int(progress * 100))%")
}
})
print("Распаковка завершена!")
} catch {
print("Ошибка распаковки: \(error.localizedDescription)")
}