let data = "InPractiseThisWillBeAReheallyLongString"
createDir()
let docsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let ourDir = docsDir.appendingPathComponent("ourCustomDir/")
let tempDir = ourDir.appendingPathComponent("temp/")
let unzippedDir = tempDir.appendingPathComponent("unzippedDir/")
let unzippedfileDir = unzippedDir.appendingPathComponent("unZipped.txt")
let zippedDir = tempDir.appendingPathComponent("Zipped.zip")
do {
try data.write(to: unzippedfileDir, atomically: false, encoding: .utf8)
let x = SSZipArchive.createZipFile(atPath: zippedDir.path, withContentsOfDirectory: unzippedfileDir.path)
var zipData: NSData! = NSData()
do {
zipData = try NSData(contentsOfFile: unzippedfileDir.path, options: NSData.ReadingOptions.mappedIfSafe)
//once I get a readable .zip file, I will be using this zipData in a multipart webservice
}
catch let err as NSError {
print("err 1 here is :\(err.localizedDescription)")
}
}
catch let err as NSError {
print("err 3 here is :\(err.localizedDescription)")
}
And the createDir
function is:
func createDir() {
let docsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let ourDir = docsDir.appendingPathComponent("ourCustomDir/")
let tempDir = ourDir.appendingPathComponent("temp/")
let unzippedDir = tempDir.appendingPathComponent("unzippedDir/")
let fileManager = FileManager.default
if fileManager.fileExists(atPath: tempDir.path) {
deleteFile(path: tempDir)
deleteFile(path: unzippedDir)
} else {
print("file does not exist")
do {
try FileManager.default.createDirectory(atPath: tempDir.path, withIntermediateDirectories: true, attributes: nil)
try FileManager.default.createDirectory(atPath: unzippedDir.path, withIntermediateDirectories: true, attributes: nil)
print("creating dir \(tempDir)")
} catch let error as NSError {
print("here : " + error.localizedDescription)
}
}
}
Right now I am not getting any errors but when I download my appData container, get the ZIP file and attempt to unzip, I ma told the ZIP file is empty. I can see that the unzipped.text file does exist as expected.
Any idea what I'm doing wrong?
Is there a method to create a .zip
directly from the string without having to save the file to the data container?
I also tried the following and have the exact same results:
let zipArch = SSZipArchive(path: zippedDir.path)
print(zipArch.open)
print(zipArch.write(dataStr.data(using: String.Encoding.utf8)!, filename: "blah.txt", withPassword: ""))
print(zipArch.close)
I did it with ZipFoundation --> https://github.com/weichsel/ZIPFoundation
SWIFT
100% Working!!
1) Add ZipFoundation Framework to your project
2) Add import to your class
import ZIPFoundation //Add to top of your class
Call Function
zipString() . // Do your work
extract(fileName: "myZip.zip") //Extract it to test it
read(fileName : "zipTxt.txt" ) //Read you extracted File
Add function to your class
func zipString() {
let zipName = "myZip.zip"
let myTxtName = "zipTxt.txt"
let myString = "I love to zip files" // In your case "InPractiseThisWillBeAReheallyLongString"
if let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
let fileURL = dir.appendingPathComponent(zipName)
//Create the zip file
guard let archive = Archive(url: fileURL, accessMode: .create) else {
return
}
/* guard let archive = Archive(url: fileURL, accessMode: .update) else {
return
} */ // In case you want to update
print("CREATED")
//Add file to
let data = myString.data(using: .utf8)
try? archive.addEntry(with: myTxtName, type: .file, uncompressedSize: UInt32(data!.count), compressionMethod: .deflate, provider: { (position, size) -> Data in
return data!
})
print("ADDED")
}
}
Bonus File Extraction
/**
** Extract file for a given name
**/
func extract(fileName : String){
let fileManager = FileManager()
let file = fileName
// let currentWorkingPath = fileManager.currentDirectoryPath
if let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
let fileURL = dir.appendingPathComponent(file)
do {
// try fileManager.createDirectory(at: dir, withIntermediateDirectories: true, attributes: nil)
try fileManager.unzipItem(at: fileURL, to: dir)
print("EXTRACTED")
} catch {
print("Extraction of ZIP archive failed with error:\(error)")
}
}
}
For testing your extracted file
func read(fileName : String){
let file = fileName //this is the file. we will write to and read from it
if let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
let fileURL = dir.appendingPathComponent(file)
//reading
do {
let text2 = try String(contentsOf: fileURL, encoding: .utf8)
print(text2)
}
catch {/* error handling here */}
}
}
My Console Output...
CREATED
ADDED
EXTRACTED
I love to zip files
Little note: You can zip anything without using third party libraries ;)
/// Zip the itemAtURL (file or folder) into the destinationFolderURL with the given zipName
/// - Parameters:
/// - itemURL: File or folder to zip
/// - destinationFolderURL: destination folder
/// - zipName: zip file name
/// - Throws: Error in case of failure in generating or moving the zip
func zip(itemAtURL itemURL: URL, in destinationFolderURL: URL, zipName: String) throws {
var error: NSError?
var internalError: NSError?
NSFileCoordinator().coordinate(readingItemAt: itemURL, options: [.forUploading], error: &error) { (zipUrl) in
// zipUrl points to the zip file created by the coordinator
// zipUrl is valid only until the end of this block, so we move the file to a temporary folder
let finalUrl = destinationFolderURL.appendingPathComponent(zipName)
do {
try FileManager.default.moveItem(at: zipUrl, to: finalUrl)
} catch let localError {
internalError = localError as NSError
}
}
if let error = error {
throw error
}
if let internalError = internalError {
throw internalError
}
}
You could use ZIPFoundation, which is another Swift ZIP library that allows you to read, create and modify ZIP files. One of its advantages is that it allows you to add ZIP entries "on-the-fly". You don't have to write your string to disk before creating an archive from it. It provides a closure based API where you can feed the string directly into a newly created archive:
func zipString() {
let string = "InPractiseThisWillBeAReheallyLongString"
var archiveURL = URL(fileURLWithPath: NSTemporaryDirectory())
archiveURL.appendPathComponent(ProcessInfo.processInfo.globallyUniqueString)
archiveURL.appendPathExtension("zip")
guard let data = string.data(using: .utf8) else { return }
guard let archive = Archive(url: archiveURL, accessMode: .create) else { return }
try? archive.addEntry(with: "unZipped.txt", type: .file, uncompressedSize: UInt32(data.count), provider: { (position, size) -> Data in
return data
})
}
The addEntry
method also has an optional bufferSize
parameter that can be used to perform chunked addition (so that you don't have to load the whole data object into RAM.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With