I'm trying to achieve a very simple thing in my iOS app: zip a file in Documents
folder. I wrote the following FileManager
extension:
extension FileManager {
func zipFile(url: URL, deleteOriginal: Bool = false) {
guard let fileData = try? Data(contentsOf: url) else { return }
let nsdata = fileData as NSData
let zipped: NSData
zipped = (try? nsdata.compressed(using: .zlib)) ?? nsdata
let zip = zipped as Data
let zipUrl = url.deletingPathExtension().appendingPathExtension("zip")
try? FileManager.default.removeItem(at: zipUrl)
try? zip.write(to: zipUrl)
if deleteOriginal {
try? FileManager.default.removeItem(at: url)
}
}
}
However, the created file seems to be is corrupted.
I go to Xcode -> Window -> Devices and Simulators, select my device, then my app in the list below it, click the gear button under the list and then click on Download Container... to see the files. Then I open the contents of the downloaded package and check the Documents folder - it has the created zip file in it. However, I cannot open it. By default Mac creates a file with zip.cpgz
extension which it usually does when the file is corrupted. Other extractor apps show an error message telling the file is corrupted. When I try to open it in the terminal using unzip
I see the following message:
iMac:Downloads user$ unzip myzip.zip
Archive: myzip.zip
End-of-central-directory signature not found. Either this file is not
a zipfile, or it constitutes one disk of a multi-part archive. In the
latter case the central directory and zipfile comment will be found on
the last disk(s) of this archive.
unzip: cannot find zipfile directory in one of myzip.zip or
myzip.zip.zip, and cannot find myzip.zip.ZIP, period.
I tried not only NSData.compressed
, but also a library called DataCompression, and also implemented compression "myself" using Apple instructions from here. In all of the cases the file was corrupted the same way.
I also tried to debug my code, displayed the compressed Data object in debugger and export it as a file. Again corrupted with the same symptoms.
Is there something that I'm doing wrong? Please let me know how to compress and save stuff to a file, not just [NS]Data, like in most of the answers in StackOverflow.
ZIP is an archive file format which also supports compression (but it can also contain uncompressed files).
A ZIP archive contains more than just the compressed file contents. It also maintains an index of all files, directories & symlinks. This index is called Central Directory and it is appended to the end of the file. Additionally each file in the archive also gets some metadata attached. This local file header carries information such as file creation date, file attributes, file paths, ...
You can find a full specification of the ZIP format here.
I published a small framework that can be used to work with ZIP archives in Swift: https://github.com/weichsel/ZIPFoundation
Using this framework, you can create an archive from a single file by using the following code:
let fileManager = FileManager()
let currentWorkingPath = fileManager.currentDirectoryPath
var sourceURL = URL(fileURLWithPath: currentWorkingPath)
sourceURL.appendPathComponent("file.txt")
var destinationURL = URL(fileURLWithPath: currentWorkingPath)
destinationURL.appendPathComponent("archive.zip")
do {
try fileManager.zipItem(at: sourceURL, to: destinationURL)
} catch {
print("Creation of ZIP archive failed with error:\(error)")
}