关于
UnzipKit 是 Objective-C 对 zlib
的封装,用于在 OS X 和 iOS 上压缩和解压缩 Zip 文件。它基于 AgileBits 分支的 Objective-Zip,由 Flying Dolphin Studio 开发。
与 Objective-Zip 相比,它提供了以下特性:
- 更简单的 API,只有一个少量方法,且无需记忆咒语
- 能够在归档中删除文件,包括覆盖现有文件
- 广泛使用 block,使迭代简单
- 所有方法的完整文档
- 广泛使用
NSError
,而不是抛出异常
安装
UnzipKit 支持同时使用 CocoaPods 和 Carthage。CocoaPods 不支持动态框架目标(截至 v0.39.0 版本),因此在这种情况下,请使用 Carthage。
Cartfile
github "abbeycode/UnzipKit"
Podfile
pod "UnzipKit"
删除文件
使用《-deleteFile:error:》方法目前在临时位置创建新的归档副本,但没有删除的文件,然后替换原始归档。默认情况下,所有写入数据的方法在归档新数据之前都会删除所写入的文件名。通过调用带有overwrite
参数的重载函数并将它设置为NO
,您可以关闭此功能。但这不会删除该文件的原始副本,从而在每个同名文件的写入时使归档增长。
如果您不关心这个问题,例如从头开始创建一个新的归档,这将提高性能,特别是对于包含大量文件的归档。
NSError *archiveError = nil;
UZKArchive *archive = [UZKArchive zipArchiveAtPath:@"An Archive.zip" error:&archiveError];
BOOL deleteSuccessful = [archive deleteFile:@"dir/anotherFilename.jpg"
error:&error];
检测 Zip 文件
您可以使用快速且高效的方式来检查给定路径或 URL 上的文件是否为 Zip 归档。
BOOL fileAtPathIsArchive = [UZKArchive pathIsAZip:@"some/file.zip"];
NSURL *url = [NSURL fileURLWithPath:@"some/file.zip"];
BOOL fileAtURLIsArchive = [UZKArchive urlIsAZip:url];
读取 Zip 内容
NSError *archiveError = nil;
UZKArchive *archive = [UZKArchive zipArchiveAtPath:@"An Archive.zip" error:&archiveError];
NSError *error = nil;
您可以使用 UnzipKit 执行这些只读操作。
-
列出归档内容。
NSArray<NSString*> *filesInArchive = [archive listFilenames:&error];
-
将所有文件提取到磁盘。
BOOL extractFilesSuccessful = [archive extractFilesTo:@"some/directory" overWrite:NO error:&error];
-
将归档中的每个文件提取到内存中。
NSData *extractedData = [archive extractDataFromFile:@"a file in the archive.jpg" error:&error];
修改归档
NSError *archiveError = nil;
UZKArchive *archive = [UZKArchive zipArchiveAtPath:@"An Archive.zip" error:&archiveError];
NSError *error = nil;
NSData *someFile = // Some data to write
您还可以修改 Zip 归档。
-
将内存中的
NSData
写入归档。BOOL success = [archive writeData:someFile filePath:@"dir/filename.jpg" error:&error];
-
带有自定义属性的
NSData
写入归档。Objective-C
ZipFileProperties *props = [[ZipFileProperties alloc] init:someFile]; props.password = @"secret"; BOOL success = [archive writeData:someFile filePath:@"dir/filename.jpg" error:&error];
Swift
do { let props = ZipFileProperties(filePath) props.password = "secret" try archive.write(someFile, props: props) } catch let error as NSError { NSLog("Error writing to file \(filePath): \(error)") }
-
以流的方式将数据写入归档(从磁盘或通过网络),使用代码块。
BOOL success = [archive writeIntoBufferAtPath:@"dir/filename.png" error:&error block: ^BOOL(BOOL(^writeData)(const void *bytes, unsigned int length), NSError**(actionError)) { for (NSUInteger i = 0; i <= someFile.length; i += bufferSize) { const void *bytes = // some data unsigned int length = // length of data if (/* Some error occurred reading the data */) { *actionError = // Any error that was produced, or make your own return NO; } if (!writeData(&bytes, length)) { return NO; } } return YES; }];
-
从归档中删除文件。
BOOL success = [archive deleteFile:@"No-good-file.txt" error:&error];
进度报告
以下方法支持NSProgress
和NSProgressReporting
。
extractFilesTo:overwrite:error
extractData:error
extractDataFromFile:error
performOnFilesInArchive:error
performOnDataInArchive:error
extractBufferedDataFromFile:error:action
writeData:filePath:error
*writeData:props:error
*
_* writeData...
方法不支持取消,就像只读方法那样。
NSProgress
层次结构
使用隐式 您可以根据以下方式创建自己的 NSProgress
实例并利用键值观察 (KVO) 监视其 fractionCompleted
属性来监控进度:
static void *ExtractDataContext = &ExtractDataContext;
UZKArchive *archive = [[UZKArchive alloc] initWithURL:aFileURL error:nil];
NSProgress *extractDataProgress = [NSProgress progressWithTotalUnitCount:1];
[extractDataProgress becomeCurrentWithPendingUnitCount:1];
NSString *observedSelector = NSStringFromSelector(@selector(fractionCompleted));
[extractDataProgress addObserver:self
forKeyPath:observedSelector
options:NSKeyValueObservingOptionInitial
context:ExtractDataContext];
NSError *extractError = nil;
NSData *data = [archive extractDataFromFile:firstFile error:&extractError];
[extractDataProgress resignCurrent];
[extractDataProgress removeObserver:self forKeyPath:observedSelector];
NSProgress
实例
使用自己显式的 如果您没有 NSProgress
实例的层次结构,或者您想在 extractFilesTo:overwrite:error:
中的进度更新期间观察更多细节,您可以创建自己的 NSProgress
实例并设置 UZKArchive
实例的 progress
属性,如下所示:
static void *ExtractFilesContext = &ExtractFilesContext;
UZKArchive *archive = [[UZKArchive alloc] initWithURL:aFileURL error:nil];
NSProgress *extractFilesProgress = [NSProgress progressWithTotalUnitCount:1];
archive.progress = extractFilesProgress;
NSString *observedSelector = NSStringFromSelector(@selector(localizedDescription));
[self.descriptionsReported removeAllObjects];
[extractFilesProgress addObserver:self
forKeyPath:observedSelector
options:NSKeyValueObservingOptionInitial
context:ExtractFilesContext];
NSError *extractError = nil;
BOOL success = [archive extractFilesTo:extractURL.path
overwrite:NO
error:&extractError];
[extractFilesProgress removeObserver:self forKeyPath:observedSelector];
NSProgress
取消
使用 使用上述任何一种方法,您都可以调用 [progress cancel]
来停止当前的操作。这将导致操作失败,返回 nil
或 NO
(取决于返回类型),并给出错误代码 UZKErrorCodeUserCancelled
的错误。
注意:取消操作仅在解压方法上受支持,不支持写入方法。_
文档
该项目的完整文档可在 CocoaDocs 上找到。
日志记录
从 2016 年开始的所有 OS 版本(macOS 10.12、iOS 10、tvOS 10、watchOS 3)中,UnzipKit 使用新的 Unified Logging 框架 进行日志记录和活动跟踪。您可以在 Info 或 Debug 级别查看消息以查看 UnzipKit 的工作细节,并使用活动跟踪帮助定位导致特定错误的代码路径。
作为回退,旧操作系统上使用常规的 NSLog
,所有消息都记录在相同级别。
当调试自己的代码时,如果您想降低UnzipKit框架的详细程度,可以运行以下命令
sudo log config --mode "level:default" --subsystem com.abbey-code.UnzipKit
可用的级别,按详细程度递增的顺序是 default
(默认),info
,debug
,其中debug
是默认。
日志记录指南
这些是关于如何分类和编写操作和日志消息的通用规则。它们是在初次日志消息阶段之后编写的,因此可能存在一些不一致(如错误的日志级别)。如果您认为您发现了错误,请提出一个问题或Pull请求!
日志记录
日志消息应遵循以下约定。
- 日志消息没有结尾标点(如这些列表项)
- 指出即将调用C函数的消息,而不是调用更高层次的UnzipKit或Cocoa方法,以"..."结尾,因为这些不应记录任何细节
默认日志级别
此级别不应有任何消息,这样API的消费者就可以像上面详细说明的那样关闭所有诊断日志。仅可以为进程而不是子系统进行log config --mode "level:off"
。
Info级别日志
Info级别日志语句服务于以下特定目的。
- 执行主要操作,例如初始化存档对象或从存档中删除文件
- 指出每个公共方法已被调用,以及调用它的参数
- 标记公共方法将采取的主要操作
- 通知发生了异常条件(例如,导致块早停或无返回值的操作)
- 指出将发生循环,其中包含每个迭代的调试级别消息
调试日志级别
大多数消息属于此类,因此非常详尽。所有不属于其他两个类别的非错误消息都应该是调试级别,以下是一些具体情况的例子。
- 任何私有方法中的日志消息
- 方法中记录变量和参数值
- 指示一切运行如预期
- 指示循环的每次迭代中发生的事情(或记录迭代已发生)
错误日志级别
- 每个生成的
NSError
都应该以与NSError
对象本身相同的详细信息消息进行记录 NSError
日志消息应包含在设计和实现时已知错误码枚举值的字符串(例如"UZKErrorCodeArchiveNotFound"
)- 应该在每个遇到错误的地方报告错误,使其更容易追踪它们的调用栈流程
- 导致所需工作不执行的双重退出
故障日志级别
到目前为止,只有一个情况在故障级别记录:当 Cocoa 框架的返回错误时
活动
- 公共方法有带空格的英文活动名称,并且是标题大小写
- 每个私有方法都有自己的活动名,与方法的名称相同
- 为重要的范围变化创建子活动,例如在动作块内,但如果在进入该动作之前没有进行任何重大工作,则不会创建子活动
- 方法中的顶级活动具有名为
activity
的变量,子活动赋予更具体的标签 - 如果一个方法是严格的重载,调用另一个重载而没有做任何其他事情,则不应定义其自己的活动
推送到新的 CocoaPods 版本
满足以下条件的任何分支的标签构建都会自动推送到 CocoaPods:
- 所有构建和测试均成功
- 库可以成功构建为 CocoaPods 和 Carthage
- 构建被标记为类似于版本号的东西(例如
#.#.#( -beta #)
,例如 2.9 或 2.9-beta5) pod spec lint
通过,确保 CocoaPod 100% 有效
在推送构建之前,您必须
-
将发布说明添加到 CHANGELOG.md,并提交
-
运行 set-version,如下所示
./Scripts/set-version.sh <版本号>
这将执行以下操作
- 更新各种 Info.plist 文件以指示新的版本号,并提交它们
- 创建一个带注释的标签,其消息包含在步骤 1 中输入的发布说明
完成这些操作后,您可以调用 git push --follow-tags
1,并让 Travis CI 处理其余部分。
重新在 CocoaPods 中注册
如果您在构建的发布阶段看到此消息,您需要从 CocoaPods 获取新的身份验证令牌
身份验证令牌无效或未经验证。请使用收到的电子邮件或重新注册会话进行验证
- 本地调用:
pod trunk register _pod owner email address_ --description='_describe machine_'
- 点击 CocoaPods 发送的电子邮件中的验证链接
- 打开 ~/.netrc,找到类似以下内容的部分:machine trunk.cocoapods.org login [email protected] password 0000000011111111
- 在 Travis CI 中更新令牌
- 转到 计划设置
- 删除
COCOAPODS_TRUNK_TOKEN
- 创建一个新环境变量
- 名称:COCOAPODS_TRUNK_TOKEN
- 值:0000000011111111(替换为上面您在本地机器上找到的值)
- 分支:所有分支
- 显示构建日志中的值:不勾选
- 重新运行发布阶段
许可协议
- UnzipKit:查看 LICENSE (BSD)(链接打开的确定为 "BSD")
- MiniZip:查看 MiniZip 网站
1:或者在本地的 git 配置中将 followTags = true
设置为默认行为
git config --global push.followTags true