ZIPFoundation
ZIPFoundation copied to clipboard
Unzipping in-memory archive
Is your feature request related to a problem? Please describe.
It doesn't seem like there's a way to unzip an in-memory archive created with Archive(data:)
initializer.
Describe the solution you'd like
An extension function on FileManager
that takes an instance of Archive
as an argument and unzips the archive in a given directory.
Describe alternatives you've considered
I've tried writing an in-memory archive to the filesystem first and then using the existing unzipItem
extension function on FileManager
, but that has a performance hit due to the fact that this requires writing the archive itself to disk.
Additional context Writing the archive to disk is not needed in my case, it's held entirely in memory as it was donwloaded from network and there's no need to write the archive itself to disk, the app needs to write unzipped archive content directly to disk. The in-memory zip data is immediately discarded.
Hi Max,
Sorry for the delayed reply.
There are currently no convenience methods on FileManager
to extract in-memory archives. There is a pending PR that implements this though. I will need to find some time to review it and fix some minor issues before we can merge this into master - but at a first glance the PR additions look good. So you can maybe use the PR branch or copy the unzipItem
code into a category.
A workaround I'm currently using is extracting each entry individually in an archive. The destination could be either on disk or in memory. This is also how zipping and unzipping an entire archive works internally in ZIP Foundation.
A workaround I'm currently using is extracting each entry individually in an archive. The destination could be either on disk or in memory. This is also how zipping and unzipping an entire archive works internally in ZIP Foundation.
Can u tell me how u did it? I struggle to unpack the password protected archive to memory.
This is really awesome ... in-memory unzipping! I wrote a small app to test this, using cocoapods to import the dependency. It is unclear to me how I can get the unzipped file. Perhaps somebody can explain that?
I would expect I have to do something like this:
// data contains the zipped data
let archive = ZIPFoundation.Archive(data: data, accessMode: .read)
for entry in archive! {
print(entry.path) // Here I succesfully print the paths of the zipped components inside the zipfile
if entry.type == .file,
let data = entry.dataDescriptor?.data {
}
}
But that gives me an error: "'dataDescriptor' is inaccessible due to 'internal' protection level"
How do I get the unzipped data for an entry? Or should I not look at the entries?
I solved it:
if let archive = ZIPFoundation.Archive(data: data, accessMode: .read) {
for entry in archive {
do {
if entry.path == "myfile.text" {
var txtData = Data()
_ = try archive.extract(entry) { data in
txtData.append(data)
}
// here we have our unzipped text (in txtData)!!
}
} catch {
print(error)
}
}
}
Awesome!
@danio0701 Sorry for this really really late response!
The way I did it (here in this semi-abandoned project) is mostly the same as how @Yourney did it. The only thing I want to mention is that, depending on whether you want the entire directory structure, or just the files, or any specific file, you can guard
against the rest or supply a where
clause to the loop:
guard let archive = Archive(data: yourData, accessMode: .read) else { ... }
for entry in archive where entry.type == .file /* or .directory depending on your need */ {
do {
_ = try archive.extract(entry, skipCRC32: true, progress: nil) { data in
// do what you need with the data
// e.g. reassemble the directory structure here if you need it
}
} catch { ... }
}
Thanks for the added tips!