Trabalhando com ZIP/arquivos em Swift (iOS/macOS)
No desenvolvimento moderno para iOS e macOS, frequentemente surge a necessidade de compactar e descompactar arquivos. Os arquivos ZIP são uma forma padrão de compressão de dados, suportada em todas as plataformas Apple. Neste artigo, veremos os recursos nativos do Swift para trabalhar com ZIP, bem como a biblioteca popular ZIPFoundation.
Recursos nativos do Foundation
O framework Foundation fornece capacidades básicas para trabalhar com arquivos através da classe NSFileCoordinator e utilitários do sistema. No entanto, para um trabalho completo com ZIP, é recomendado usar bibliotecas de terceiros ou wrappers sobre comandos do sistema.
Biblioteca ZIPFoundation
ZIPFoundation é uma biblioteca leve para trabalhar com arquivos ZIP, escrita em Swift puro. Ela suporta iOS, macOS, tvOS e watchOS, não requer dependências externas e é distribuída sob a licença MIT.
Instalação via Swift Package Manager
Adicione a dependência no Package.swift:
dependencies: [ .package(url: "https://github.com/weichsel/ZIPFoundation.git", from: "0.9.16")]Ou via Xcode: File → Add Packages → insira a URL do repositório.
Operações principais
1. Criando um arquivo ZIP
Compactando um único arquivo:
import ZIPFoundation
let fileManager = FileManager.defaultlet sourceURL = URL(fileURLWithPath: "/path/to/file.txt")let destinationURL = URL(fileURLWithPath: "/path/to/archive.zip")
do { try fileManager.zipItem(at: sourceURL, to: destinationURL) print("Arquivo criado: \\(destinationURL.path)")} catch { print("Erro: \\(error.localizedDescription)")}Compactando um diretório inteiro:
let directoryURL = URL(fileURLWithPath: "/path/to/folder")let archiveURL = URL(fileURLWithPath: "/path/to/folder.zip")
do { try fileManager.zipItem(at: directoryURL, to: archiveURL) print("Diretório compactado")} catch { print("Erro: \\(error)")}2. Extraindo um arquivo
let archiveURL = URL(fileURLWithPath: "/path/to/archive.zip")let destinationURL = URL(fileURLWithPath: "/path/to/unzip")
do { try fileManager.unzipItem(at: archiveURL, to: destinationURL) print("Extração concluída")} catch { print("Erro na extração: \\(error)")}3. Trabalhando com o conteúdo do arquivo sem extrair
guard let archive = Archive(url: archiveURL, accessMode: .read) else { fatalError("Não foi possível abrir o arquivo")}
// Lista de todas as entradasfor entry in archive { print("Arquivo: \\(entry.path), tamanho: \\(entry.uncompressedSize) bytes")}
// Lendo um arquivo específicoif let entry = archive["documents/report.pdf"] { var data = Data() do { _ = try archive.extract(entry, bufferSize: 4096) { partialData in data.append(partialData) } print("Extraído \\(data.count) bytes") } catch { print("Erro: \\(error)") }}4. Adicionando arquivos a um arquivo existente
guard let archive = Archive(url: archiveURL, accessMode: .update) else { fatalError("Não foi possível abrir o arquivo para atualização")}
let newFileURL = URL(fileURLWithPath: "/path/to/new_file.txt")do { try archive.addEntry(with: "new_file.txt", relativeTo: newFileURL.deletingLastPathComponent()) print("Arquivo adicionado")} catch { print("Erro: \\(error)")}Trabalhando com progresso e arquivos grandes
Para arquivos grandes, use Progress:
let progress = Progress(totalUnitCount: 100)let archiveURL = URL(fileURLWithPath: "/path/to/large.zip")let destinationURL = URL(fileURLWithPath: "/path/to/output")
do { try FileManager.default.unzipItem(at: archiveURL, to: destinationURL, progress