Skip to content

Instantly share code, notes, and snippets.

@amayatsky
Forked from marcprux/NSURL+Zip.swift
Last active June 9, 2018 07:01
Show Gist options
  • Save amayatsky/e820d4860f50a5f078a81c9aa041e110 to your computer and use it in GitHub Desktop.
Save amayatsky/e820d4860f50a5f078a81c9aa041e110 to your computer and use it in GitHub Desktop.
Categories on URL and Data to create a zip archive without any external dependencies
public extension URL {
/// Creates a zip archive of the file/folder represented by this URL and returns a references to the zipped file
///
/// - parameter dest: the destination URL; if nil, the destination will be this URL with ".zip" appended
func zip(dest: URL? = nil) throws -> URL {
let destURL = dest ?? self.appendingPathExtension("zip")
let fm = FileManager.default
var isDir: ObjCBool = false
let srcDir: URL
let srcDirIsTemporary: Bool
if !self.path.isEmpty && self.isFileURL && fm.fileExists(atPath: path, isDirectory: &isDir) && isDir.boolValue == true {
// this URL is a directory: just zip it in-place
srcDir = self
srcDirIsTemporary = false
} else {
// otherwise we need to copy the simple file to a temporary directory in order for
// NSFileCoordinatorReadingOptions.ForUploading to actually zip it up
srcDir = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(NSUUID().uuidString)
try fm.createDirectory(at: srcDir, withIntermediateDirectories: true, attributes: nil)
let tmpURL = srcDir.appendingPathComponent(self.lastPathComponent.isEmpty ? "file" : self.lastPathComponent)
try fm.copyItem(at: self, to: tmpURL)
srcDirIsTemporary = true
}
let coord = NSFileCoordinator()
var preBlockError: NSError?
var blockError: NSError?
// coordinateReadingItemAtURL is invoked synchronously, but the passed in zippedURL is only valid
// for the duration of the block, so it needs to be copied out
coord.coordinate(readingItemAt: srcDir, options: NSFileCoordinator.ReadingOptions.forUploading, error: &preBlockError) { (zippedURL: URL) -> Void in
do {
try fm.copyItem(at: zippedURL, to: destURL)
} catch let err {
blockError = err as NSError
}
}
if srcDirIsTemporary { try fm.removeItem(at: srcDir) }
if let error = preBlockError ?? blockError { throw error }
return destURL
}
/// Creates a zip archive of the file/folder represented by this URL and returns the zipped contents
func zipToData() throws -> Data {
let zipURL = try self.zip()
let fm = FileManager.default
let zippedData = try Data(contentsOf: zipURL, options: NSData.ReadingOptions())
try fm.removeItem(at: zipURL) // clean up
return zippedData
}
}
public extension Data {
/// Creates a zip archive of this data via a temporary file and returns the zipped contents
func zip() throws -> Data {
let tmpURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(NSUUID().uuidString)
try self.write(to: tmpURL, options: NSData.WritingOptions.atomic)
let zipURL = try tmpURL.zip()
let fm = FileManager.default
let zippedData = try Data(contentsOf: zipURL, options: NSData.ReadingOptions())
try fm.removeItem(at: tmpURL) // clean up
try fm.removeItem(at: zipURL)
return zippedData
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment