Swift如何检测zip压缩包内是否包含视频内容?
Swift 检测ZIP压缩包是否包含视频内容实现方案
要实现带视频的ZIP包禁止预览的需求,核心逻辑是读取ZIP包内的文件清单,匹配常见视频文件后缀即可,不需要完整解压ZIP包,性能开销极低。
方案1:使用ZIPFoundation实现(推荐,代码量少)
ZIPFoundation是Swift原生的ZIP处理库,可通过SPM直接集成,实现代码如下:
import ZIPFoundation // 传入zip文件的本地URL,返回是否包含视频文件 func isZipContainsVideo(zipPath: URL) -> Bool { // 可根据业务需求扩展需要拦截的视频后缀 let videoSuffixSet: Set<String> = ["mp4", "mov", "avi", "mkv", "flv", "wmv", "m4v", "webm", "mpeg", "mpg"] // 只读模式打开ZIP包,不会执行解压 guard let zipArchive = Archive(url: zipPath, accessMode: .read) else { return false } // 遍历ZIP内所有文件条目 for entry in zipArchive where entry.type == .file { let fileSuffix = entry.path.lowercased().components(separatedBy: ".").last ?? "" if videoSuffixSet.contains(fileSuffix) { return true } } return false }
调用逻辑:在初始化UIDocumentInteractionController触发预览前,先调用上述方法,若返回true则直接拦截预览,返回false再执行预览逻辑即可。
方案2:使用系统Compression框架实现(无第三方依赖)
如果不想引入外部依赖,可以直接解析ZIP的二进制结构读取文件清单,实现代码如下:
import Foundation import Compression func isZipContainsVideoSystemImpl(zipPath: URL) -> Bool { let videoSuffixSet: Set<String> = ["mp4", "mov", "avi", "mkv", "flv", "wmv", "m4v", "webm", "mpeg", "mpg"] guard let zipData = try? Data(contentsOf: zipPath) else { return false } // 定位ZIP中央目录结束标记 var offset = zipData.count - 22 let endOfCentralDirSignature: UInt32 = 0x06054b50 while offset >= 0 { let signature = zipData.withUnsafeBytes { $0.load(fromByteOffset: offset, as: UInt32.self) } if signature == endOfCentralDirSignature { // 读取中央目录起始偏移 let centralDirOffset = zipData.withUnsafeBytes { $0.load(fromByteOffset: offset + 16, as: UInt32.self) } let centralDirSize = zipData.withUnsafeBytes { $0.load(fromByteOffset: offset + 12, as: UInt32.self) } var currentOffset = Int(centralDirOffset) let centralDirEnd = currentOffset + Int(centralDirSize) let centralFileHeaderSig: UInt32 = 0x02014b50 while currentOffset < centralDirEnd { let headerSig = zipData.withUnsafeBytes { $0.load(fromByteOffset: currentOffset, as: UInt32.self) } guard headerSig == centralFileHeaderSig else { break } let fileNameLength = zipData.withUnsafeBytes { $0.load(fromByteOffset: currentOffset + 28, as: UInt16.self) } let extraFieldLength = zipData.withUnsafeBytes { $0.load(fromByteOffset: currentOffset + 30, as: UInt16.self) } let commentLength = zipData.withUnsafeBytes { $0.load(fromByteOffset: currentOffset + 32, as: UInt16.self) } let fileNameStart = currentOffset + 46 guard fileNameStart + Int(fileNameLength) <= zipData.count else { break } let fileNameData = zipData.subdata(in: fileNameStart..<fileNameStart + Int(fileNameLength)) if let fileName = String(data: fileNameData, encoding: .utf8)?.lowercased() { let suffix = fileName.components(separatedBy: ".").last ?? "" if videoSuffixSet.contains(suffix) { return true } } currentOffset += 46 + Int(fileNameLength) + Int(extraFieldLength) + Int(commentLength) } break } offset -= 1 } return false }
注意事项
- 两种方案都仅读取ZIP的文件头信息,不会解压完整文件,大体积ZIP包也可以快速完成检测
- 可根据业务场景自行扩展
videoSuffixSet集合内的视频后缀,覆盖所有需要拦截的视频格式 - 检测不包含视频后,再正常调用
UIDocumentInteractionController的相关方法实现ZIP预览即可
内容的提问来源于stack exchange,提问作者Sudhi 9135
相关产品推荐
相关产品推荐

