UnzipKit 2.0-beta3

UnzipKit 2.0-beta3

测试已测试
语言语言 CC
许可协议 BSD-2-Clause
发布最近发布2021年3月

Dov Frankel 维护。



UnzipKit 2.0-beta3

Build Status Documentation Coverage

关于

UnzipKit 是 Objective-C 对 zlib 的封装,用于在 OS X 和 iOS 上压缩和解压缩 Zip 文件。它基于 AgileBits 分支的 Objective-Zip,由 Flying Dolphin Studio 开发。

与 Objective-Zip 相比,它提供了以下特性:

  • 更简单的 API,只有一个少量方法,且无需记忆咒语
  • 能够在归档中删除文件,包括覆盖现有文件
  • 广泛使用 block,使迭代简单
  • 所有方法的完整文档
  • 广泛使用 NSError,而不是抛出异常

安装

UnzipKit 支持同时使用 CocoaPodsCarthage。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];

进度报告

以下方法支持NSProgressNSProgressReporting

  • 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] 来停止当前的操作。这将导致操作失败,返回 nilNO(取决于返回类型),并给出错误代码 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(默认),infodebug,其中debug是默认。

日志记录指南

这些是关于如何分类和编写操作和日志消息的通用规则。它们是在初次日志消息阶段之后编写的,因此可能存在一些不一致(如错误的日志级别)。如果您认为您发现了错误,请提出一个问题或Pull请求!

日志记录

日志消息应遵循以下约定。

  1. 日志消息没有结尾标点(如这些列表项)
  2. 指出即将调用C函数的消息,而不是调用更高层次的UnzipKit或Cocoa方法,以"..."结尾,因为这些不应记录任何细节

默认日志级别

此级别不应有任何消息,这样API的消费者就可以像上面详细说明的那样关闭所有诊断日志。仅可以为进程而不是子系统进行log config --mode "level:off"

Info级别日志

Info级别日志语句服务于以下特定目的。

  1. 执行主要操作,例如初始化存档对象或从存档中删除文件
  2. 指出每个公共方法已被调用,以及调用它的参数
  3. 标记公共方法将采取的主要操作
  4. 通知发生了异常条件(例如,导致块早停或无返回值的操作)
  5. 指出将发生循环,其中包含每个迭代的调试级别消息

调试日志级别

大多数消息属于此类,因此非常详尽。所有不属于其他两个类别的非错误消息都应该是调试级别,以下是一些具体情况的例子。

  1. 任何私有方法中的日志消息
  2. 方法中记录变量和参数值
  3. 指示一切运行如预期
  4. 指示循环的每次迭代中发生的事情(或记录迭代已发生)

错误日志级别

  1. 每个生成的 NSError 都应该以与 NSError 对象本身相同的详细信息消息进行记录
  2. NSError 日志消息应包含在设计和实现时已知错误码枚举值的字符串(例如 "UZKErrorCodeArchiveNotFound"
  3. 应该在每个遇到错误的地方报告错误,使其更容易追踪它们的调用栈流程
  4. 导致所需工作不执行的双重退出

故障日志级别

到目前为止,只有一个情况在故障级别记录:当 Cocoa 框架的返回错误时

活动

  1. 公共方法有带空格的英文活动名称,并且是标题大小写
  2. 每个私有方法都有自己的活动名,与方法的名称相同
  3. 为重要的范围变化创建子活动,例如在动作块内,但如果在进入该动作之前没有进行任何重大工作,则不会创建子活动
  4. 方法中的顶级活动具有名为 activity 的变量,子活动赋予更具体的标签
  5. 如果一个方法是严格的重载,调用另一个重载而没有做任何其他事情,则不应定义其自己的活动

推送到新的 CocoaPods 版本

满足以下条件的任何分支的标签构建都会自动推送到 CocoaPods:

  1. 所有构建和测试均成功
  2. 库可以成功构建为 CocoaPods 和 Carthage
  3. 构建被标记为类似于版本号的东西(例如 #.#.#( -beta #),例如 2.92.9-beta5
  4. pod spec lint 通过,确保 CocoaPod 100% 有效

在推送构建之前,您必须

  1. 将发布说明添加到 CHANGELOG.md,并提交

  2. 运行 set-version,如下所示

    ./Scripts/set-version.sh <版本号>

    这将执行以下操作

    1. 更新各种 Info.plist 文件以指示新的版本号,并提交它们
    2. 创建一个带注释的标签,其消息包含在步骤 1 中输入的发布说明

完成这些操作后,您可以调用 git push --follow-tags 1,并让 Travis CI 处理其余部分。

重新在 CocoaPods 中注册

如果您在构建的发布阶段看到此消息,您需要从 CocoaPods 获取新的身份验证令牌

身份验证令牌无效或未经验证。请使用收到的电子邮件或重新注册会话进行验证

  1. 本地调用:pod trunk register _pod owner email address_ --description='_describe machine_'
  2. 点击 CocoaPods 发送的电子邮件中的验证链接
  3. 打开 ~/.netrc,找到类似以下内容的部分:machine trunk.cocoapods.org login [email protected] password 0000000011111111
  4. 在 Travis CI 中更新令牌
    1. 转到 计划设置
    2. 删除 COCOAPODS_TRUNK_TOKEN
    3. 创建一个新环境变量
      • 名称:COCOAPODS_TRUNK_TOKEN
      • 值:0000000011111111(替换为上面您在本地机器上找到的值)
      • 分支:所有分支
      • 显示构建日志中的值:不勾选
  5. 重新运行发布阶段

许可协议


1:或者在本地的 git 配置中将 followTags = true 设置为默认行为

git config --global push.followTags true