如何在Objective-C中不使用第三方库将文件夹压缩为zip格式
问题根因
你的实现从底层逻辑上就不符合ZIP格式规范,并非是遗漏写入步骤:
- 你使用的
NSDataCompressionAlgorithmZlib仅能生成原始的zlib压缩数据流,而标准ZIP归档是包含文件头标记、单文件元数据区、末尾中央目录记录的结构化格式,单纯的压缩流没有这些结构,所有解压工具自然无法识别。 NSFileWrapper的serializedRepresentation是系统用于跨进程传输、粘贴板存储的私有序列化格式,不是文件夹内所有文件的原始二进制集合,本身就不适合作为压缩归档的数据源。
系统原生实现ZIP打包的两种方案
无需引入任何第三方库,仅用系统内置能力即可实现标准ZIP打包,推荐以下两种方案:
方案1:调用系统内置命令行工具(macOS全版本兼容)
你可以通过NSTask调用系统自带的ditto命令,输出的ZIP包和访达「压缩」功能生成的文件完全一致,自动适配文件权限、资源分叉、元数据等内容:
// 源文件夹路径srcURL,输出ZIP路径dstURL NSError *error = nil; NSTask *task = [[NSTask alloc] init]; task.launchPath = @"/usr/bin/ditto"; task.arguments = @[@"-c", @"-k", @"-rsrc", @"--keepParent", srcURL.path, dstURL.path]; [task launch]; [task waitUntilExit]; if (task.terminationStatus != 0) { NSLog(@"打包失败,状态码:%d", task.terminationStatus); }
方案2:使用官方ArchiveKit框架(适配iOS15+/macOS12+及以上系统版本)
苹果在2021年推出了官方归档处理框架ArchiveKit,原生支持标准ZIP格式的读写,无需依赖任何第三方组件:
#import <ArchiveKit/ArchiveKit.h> NSError *error = nil; // 创建ZIP归档文件 ARArchive *archive = [ARArchive archiveWithURL:dstURL mode:ARArchiveModeCreate error:&error]; if (!archive) { NSLog(@"创建归档失败:%@", error.localizedDescription); return; } // 遍历源文件夹所有文件写入归档 NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtURL:srcURL includingPropertiesForKeys:@[NSURLIsDirectoryKey, NSURLFileNameKey] options:0 errorHandler:nil]; for (NSURL *fileURL in enumerator) { NSNumber *isDirectory = nil; [fileURL getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:nil]; if (isDirectory.boolValue) continue; // 跳过目录,仅处理文件 // 计算文件在归档内的相对路径 NSString *relativePath = [fileURL.path substringFromIndex:srcURL.path.length + 1]; unsigned long long fileSize = [[NSFileManager defaultManager] attributesOfItemAtPath:fileURL.path error:nil].fileSize; ARArchiveEntry *entry = [ARArchiveEntry entryWithPath:relativePath type:ARArchiveEntryTypeRegular fileSize:fileSize]; entry.compressionMethod = ARCompressionMethodDeflate; // 使用ZIP标准的deflate压缩算法 BOOL addSuccess = [archive addEntry:entry error:&error writer:^BOOL(ARArchiveEntryWriter _Nonnull writer, NSError * _Nullable * _Nonnull writeError) { NSData *fileData = [NSData dataWithContentsOfURL:fileURL options:0 error:writeError]; if (!fileData) return NO; return writer(fileData.bytes, fileData.length, writeError); }]; if (!addSuccess) { NSLog(@"添加文件%@失败:%@", relativePath, error.localizedDescription); break; } } // 关闭归档完成写入 [archive closeAndReturnError:&error];
内容的提问来源于stack exchange,提问作者dkovacev
相关产品推荐
相关产品推荐

