使用Swift解压缩zip文件

17

我用Swift制作了一个游戏,但是我需要在我的网站上下载.zip文件,并在游戏中使用其中的内容(图像)。 实际上,我下载了这个.zip文件并将其存储在文档中,我需要将文件解压缩到同一个文档文件夹中。

我尝试了marmelroy的Zip、iOS 9压缩模块和tidwall的DeflateSwift,但都没有起作用。如果它与iOS 8兼容将会很好。

6个回答

29

我最近发布了一个基于Swift的原生框架,它允许您创建、读取和更新ZIP存档文件: ZIP Foundation
它在内部使用libcompression来获得出色的压缩性能。

解压缩文件基本上只需要一行代码:

try fileManager.unzipItem(at: sourceURL, to: destinationURL)

一个带有一些上下文的完整示例看起来像这样:

let fileManager = FileManager()
let currentWorkingPath = fileManager.currentDirectoryPath
var sourceURL = URL(fileURLWithPath: currentWorkingPath)
sourceURL.appendPathComponent("archive.zip")
var destinationURL = URL(fileURLWithPath: currentWorkingPath)
destinationURL.appendPathComponent("directory")
do {
    try fileManager.createDirectory(at: destinationURL, withIntermediateDirectories: true, attributes: nil)
    try fileManager.unzipItem(at: sourceURL, to: destinationURL)
} catch {
    print("Extraction of ZIP archive failed with error:\(error)")
}

GitHub 上的README 包含更多信息。所有公共方法还可以通过 Xcode 快速帮助获得完整文档。

我还在这里写了一篇关于性能特征的博客文章。


两行try语句都会出现这个错误:对成员'fileManager(_:shouldProceedAfterError:)'的引用不明确。 - DevB2F
如何进行内存操作?https://stackoverflow.com/questions/55089278/how-can-i-get-zip-from-data-object-and-unzip-first-entry-file-inside-it - user25
目前正在开发中。已经提交了一个支持内存处理档案的PR,但是它目前在内存写入方面存在问题。读取已经可以正常工作 https://github.com/weichsel/ZIPFoundation/pull/78 - Thomas Zoechling
1
截至2020年12月,方法unzipItem()似乎不可用。 - pinglock
1
它可用且运行良好:https://github.com/weichsel/ZIPFoundation/blob/development/Sources/ZIPFoundation/FileManager%2BZIP.swift#L92 你能发布代码或你的项目设置吗?也许我可以帮忙。 - Thomas Zoechling
1
5年后,ZIPFoundation是唯一的选择,它是最好的SPMs之一。点击“添加包”并粘贴github.com/weichsel/ZIPFoundation.git,工作完成了。太棒了,ZIPFoundation! - Fattie

4
我发现了一个叫做Minizip的库。试试看吧。
你可以使用Zip框架来解压缩文件,使用Swift编写非常简单。
示例代码:
do {
    let filePath = NSBundle.mainBundle().URLForResource("file", withExtension: "zip")!
    let unzipDirectory = try Zip.quickUnzipFile(filePath) // Unzip
    let zipFilePath = try Zip.quickZipFiles([filePath], fileName: "archive") // Zip
}
catch {
  print("Something went wrong")
}

如果Minizip不起作用,您可以尝试使用ZipArchive,它不是用Swift编写的,而是用Objective-C编写的。


是的,这是我尝试的第一个方法,但当我尝试时它无法找到minizip模块。 - Snowy_1803
你可以使用ZipArchive,目前据我所知没有其他可用的框架。 - Amit Singh
使用SSZipArchive时,它找不到同名的类。 - Snowy_1803
尝试第一个,MiniZip。我已经更新了我的答案。 - Amit Singh
如果我将minizip和vendor文件夹拖放到我的项目中,它无法在我的Swift代码中找到Minizip模块。我没有使用Carthage。 - Snowy_1803
如何从“Data”对象中获取文件而不是文件?https://stackoverflow.com/questions/55089278/how-can-i-get-zip-from-data-object-and-unzip-first-entry-file-inside-it - user25

0

我使用SSZipArchive和桥接头使其工作:

  1. 将SSZipArchive目录拖放到您的项目中
  2. 创建一个{PROJECT-MODULE-NAME}-Bridging-Header.h文件,并添加以下行:import "SSZipArchive.h"
  3. 在Build Settings中,将桥接头拖放到Swift Compiler - Code generation -> Objective-C Bridging Header。
  4. 在您的Swift代码中使用SSZipArchive。

在完成上述4个步骤后,如果出现一堆链接错误,请将libz添加到您的目标中。 - DiggyJohn

0

这段代码将文件下载到文档目录并解压缩zip文件

别忘了安装ZIPFoundation

import ZIPFoundation

    func downloadAndUnzip(from urlString: String, toFolder folderName: String) {
    guard let url = URL(string: urlString) else { return }
    let session = URLSession.shared
    let documentsDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
    let folderURL = documentsDirectoryURL.appendingPathComponent(folderName, isDirectory: true)
    let fileURL = folderURL.appendingPathComponent(url.lastPathComponent)
    
    do { //Creates folder.
        try FileManager.default.createDirectory(at: folderURL, withIntermediateDirectories: true, attributes: nil)
    } catch {
        debugPrint("Could not create directory: \(error.localizedDescription)")
    }
    
    let task = session.downloadTask(with: url) { (tempLocalURL, response, error) in
        guard let tempLocalURL = tempLocalURL, error == nil else { return }
        
        do { //Moves data to created folder.
            try FileManager.default.moveItem(at: tempLocalURL, to: fileURL)
            debugPrint("ZIP File saved to: \(fileURL.path)")
            do { //Try to unzip the file.
                try FileManager.default.unzipItem(at: fileURL, to: folderURL)
                do { //Try to delete zip file.
                    try FileManager.default.removeItem(at: fileURL)
                    debugPrint("ZIP file deleted at:", fileURL)
                } catch {
                    debugPrint("Could not delete ZIP file with error: \(error.localizedDescription)", fileURL)
                }
                debugPrint("Unzip completed!", fileURL)
            } catch {
                debugPrint("Extraction of ZIP archive failed with error:\(error)")
            }
        } catch {
            debugPrint("Could not move item: \(error.localizedDescription)")
        }
    }
    task.resume()
}

0

现在使用优秀的ZIPFoundation SPM已经变得非常简单

  1. 点击“添加包”并粘贴 github.com/weichsel/ZIPFoundation.git

  2. FileManager().unzipItem(at: fromUrl, to: untoUrl)

就是这样。

你完成了。

来一杯啤酒吧。

以下是其他典型代码的完整示例:

let fromUrl = Bundle.main.url(forResource: "yourZipFile", withExtension: "zip")!
let untoUrl = FileManager().temporaryDirectory.appendingPathComponent("temp")

do {
    try FileManager.default.removeItem(at: untoUrl)
    try FileManager().createDirectory(at: untoUrl, withIntermediateDirectories: true)
    try FileManager().unzipItem(at: fromUrl, to: untoUrl, skipCRC32: true)
}
catch { print(error) }

do {
    let items = try FileManager.default
        .contentsOfDirectory(at: untoUrl, includingPropertiesForKeys: nil)
        .sorted{ $0.lastPathComponent < $1.lastPathComponent }
    
    for item in items { print(item.path) }
    blah = items.compactMap{ blah($0) }
}
catch { print(error) }

(请注意:与编程无关的小提示,每次都清空您的临时文件夹,否则您会留下其他运行中的文件!)

-2

重要提示:需要第三方库

使用这个,你可以使用这行代码:

let unzipDirectory= try Zip.quickUnzipFile(filePath) //to unZip your folder.

如果您需要更多帮助,请查看代码库。

4
这与使用第三方库有关,如果您没有使用它,这段代码将会生成编译时错误。我建议提出所使用的库的建议。 - Ahmad F

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接