Trabalhando com ZIP/arquivos em Swift (iOS/macOS)
No desenvolvimento moderno para iOS e macOS, muitas vezes é necessário compactar arquivos em arquivos ZIP ou extrair dados deles. Isso pode ser necessário para economizar espaço, transferir dados pela rede ou organizar backups. Neste artigo, abordaremos duas abordagens principais: o uso dos recursos internos do Foundation e a popular biblioteca de terceiros ZipFoundation.
Recursos internos do Foundation (NSFileCoordinator + trabalho de baixo nível)
A Apple não fornece uma API de alto nível para trabalhar com ZIP no Foundation. No entanto, a partir do iOS 12 / macOS 10.14, tornou-se possível usar NSFileCoordinator e NSFileWrapper para algumas operações. Mas para um trabalho completo com ZIP, geralmente se usa o utilitário de sistema libz através da interface C.
Exemplo: compressão de dados com libz
import Compressionimport Foundation
func compressData(_ data: Data) -> Data? { let sourceData = data as NSData let compressedData = NSMutableData(length: data.count)! var compressedSize = data.count let result = compression_encode( compressedData.mutableBytes.assumingMemoryBound(to: UInt8.self), &compressedSize, sourceData.bytes.assumingMemoryBound(to: UInt8.self), data.count, nil, COMPRESSION_ZLIB ) guard result == COMPRESSION_STATUS_OK else { return nil } compressedData.length = compressedSize return compressedData as Data}Biblioteca ZipFoundation (método recomendado)
ZipFoundation é uma biblioteca leve de código aberto para trabalhar com arquivos ZIP em Swift. Ela suporta iOS, macOS, tvOS e watchOS. Instalação via Swift Package Manager:
// Em Package.swift ou via Xcodedependencies: [ .package(url: "https://github.com/weichsel/ZIPFoundation.git", from: "0.9.0")]Principais recursos do ZipFoundation:
- Criação de arquivos ZIP a partir de arquivos e pastas
- Extração de arquivos individuais ou de todo o arquivo
- Suporte a senhas (AES-256)
- Trabalho com streams para arquivos grandes
- Compatibilidade com macOS e iOS
Exemplo 1: Criando um arquivo ZIP
import ZIPFoundationimport Foundation
func createZip(from sourceURL: URL, to destinationURL: URL) throws { let fileManager = FileManager() // Cria um arquivo a partir de uma pasta try fileManager.zipItem(at: sourceURL, to: destinationURL) // Ou a partir de um único arquivo // try fileManager.zipItem(at: sourceURL, to: destinationURL, // shouldKeepParent: false)}
// Usolet documents = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!let sourceFolder = documents.appendingPathComponent("MyData")let archiveURL = documents.appendingPathComponent("backup.zip")
do { try createZip(from: sourceFolder, to: archiveURL) print("Arquivo criado: \\(archiveURL.path)")} catch { print("Erro: \\(error)")}Exemplo 2: Extraindo um arquivo ZIP
import ZIPFoundation
func unzipArchive(at sourceURL: URL, to destinationURL: URL) throws { let fileManager = FileManager() // Cria a pasta de destino, se não existir try fileManager.createDirectory(at: destinationURL, withIntermediateDirectories: true) // Extrai try fileManager.unzipItem(at: sourceURL, to: destinationURL)}
// Usolet archiveURL = documents.appendingPathComponent("backup.zip")let extractFolder = documents.appendingPathComponent("ExtractedData")
do { try unzipArchive(at: archiveURL, to: extractFolder) print("Extração concluída")} catch {