在 Swift (iOS/macOS) 中处理 ZIP/归档文件
在现代 iOS 和 macOS 开发中,经常需要打包和解包文件。ZIP 归档是一种标准的数据压缩方式,在所有 Apple 平台上都受支持。在本文中,我们将探讨 Swift 中用于处理 ZIP 的原生工具,以及流行的 ZIPFoundation 库。
Foundation 原生工具
Foundation 框架通过 NSFileCoordinator 类和系统工具提供了基本的归档处理能力。然而,要全面处理 ZIP,建议使用第三方库或系统命令的封装。
ZIPFoundation 库
ZIPFoundation 是一个轻量级的 ZIP 归档处理库,使用纯 Swift 编写。它支持 iOS、macOS、tvOS 和 watchOS,无需外部依赖,并在 MIT 许可下发布。
通过 Swift Package Manager 安装
在 Package.swift 中添加依赖:
dependencies: [ .package(url: "https://github.com/weichsel/ZIPFoundation.git", from: "0.9.16")]或者通过 Xcode:File → Add Packages → 输入仓库 URL。
基本操作
1. 创建 ZIP 归档
打包单个文件:
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("归档已创建: \\(destinationURL.path)")} catch { print("错误: \\(error.localizedDescription)")}打包整个目录:
let directoryURL = URL(fileURLWithPath: "/path/to/folder")let archiveURL = URL(fileURLWithPath: "/path/to/folder.zip")
do { try fileManager.zipItem(at: directoryURL, to: archiveURL) print("目录已打包")} catch { print("错误: \\(error)")}2. 解压归档
let archiveURL = URL(fileURLWithPath: "/path/to/archive.zip")let destinationURL = URL(fileURLWithPath: "/path/to/unzip")
do { try fileManager.unzipItem(at: archiveURL, to: destinationURL) print("解压完成")} catch { print("解压错误: \\(error)")}3. 在不提取的情况下处理归档内容
guard let archive = Archive(url: archiveURL, accessMode: .read) else { fatalError("无法打开归档")}
// 列出所有条目for entry in archive { print("文件: \\(entry.path), 大小: \\(entry.uncompressedSize) 字节")}
// 读取特定文件if let entry = archive["documents/report.pdf"] { var data = Data() do { _ = try archive.extract(entry, bufferSize: 4096) { partialData in data.append(partialData) } print("已提取 \\(data.count) 字节") } catch { print("错误: \\(error)") }}4. 向现有归档添加文件
guard let archive = Archive(url: archiveURL, accessMode: .update) else { fatalError("无法打开归档进行更新")}
let newFileURL = URL(fileURLWithPath: "/path/to/new_file.txt")do { try archive.addEntry(with: "new_file.txt", relativeTo: newFileURL.deletingLastPathComponent()) print("文件已添加")} catch { print("错误: \\(error)")}处理进度和大文件
对于大型归档,请使用 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