Change file extension to .zip and unzip file from document folder - ios

Using Alamofire for downloading. File is being downloaded in app document folder, in attachment, there is .hub file.
I need to change .hub file to .zip than i need to unzip this file for audio file.
Code for downloading ->
func getAudioFileFromServer(url: String, uuid: String) {
let fileURL = URL(string: url)
var request = URLRequest(url:fileURL!)
request.setValue("myapikey", forHTTPHeaderField: "x-api-key")
let destination = DownloadRequest.suggestedDownloadDestination()
Alamofire.download(request, to: destination).validate().responseData { response in
debugPrint(response)
print(response.destinationURL!)
}
}
Response from server ->
file:///var/mobile/Containers/Data/Application/FC5F17C4-E8D3-4406-926A-97EB9447D87B/Documents/'bac6151ffbe74140a31408938c91fa33.hub'

To rename a file, use the function moveItem(atPath:toPath:) of FileManager
To unzip, the easiest way would be to integrate some zip library: https://github.com/ZipArchive/ZipArchive or https://github.com/marmelroy/Zip

After downloading the file change the extension to .zip with "saveFileInDirectory" method and with success block we can get the main file.
self.saveFileInDirectory(data: responce.result.value, fileName: "\(name!).zip", successblock: { (path) in
print(path!)
var filepath = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true)[0]
let url = URL(fileURLWithPath: filepath)
do {
try FileManager.default.createDirectory(at: url, withIntermediateDirectories: true, attributes: nil)
let done = SSZipArchive.unzipFile(atPath: path!, toDestination: url.path)
if done{
let items = try FileManager.default.contentsOfDirectory(atPath: url.path)
print(items)
let destinationUrl = url.appendingPathComponent(items[0])
print(destinationUrl)
}
} catch let error as NSError{
print(error)
}
})
func saveFileInDirectory(data: Data?, fileName: String?, successblock: #escaping (_ path: String?) -> Void) { // To add the image to cache for given identifier.
let paths = NSSearchPathForDirectoriesInDomains( .documentDirectory, .userDomainMask, true)[0] as String
let path = paths.appending("/\(fileName!)")
if (FileManager.default.fileExists(atPath: path)) {
try! FileManager.default.removeItem(atPath: path)
} else {
do {
try data?.write(to: URL(fileURLWithPath: path, isDirectory: false))
successblock(path)
} catch {
successblock(nil)
print("Error while caching the data in cache folder.")
}
}}

Related

Saving video in locally (directory) in Swift?

I try to save given video locally after then I need those saved videos for playing video in my app. I can't handle the saving video. Here is my saving try :
func saveVideoDocumentDirectory(url : URL){
let fileManager = FileManager.default
let paths = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent(".MOV")
do{
let videoData = try Data(contentsOf: url)
fileManager.createFile(atPath: paths as String, contents: videoData, attributes: nil)
}catch{
//
}
}
here is the get file try
func getVideo(){
let fileManager = FileManager.default
let videoPAth = (self.getDirectoryPath() as NSString).appendingPathComponent(".MOV")
if fileManager.fileExists(atPath: videoPAth){
print(videoPAth)
play(url: URL(string: videoPAth)!)
}else{
print("No Video")
}
}
here is my play video func :
func play(url : URL)
{
let player = AVPlayer(url: url)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
present(playerViewController, animated: true)
{
playerViewController.player!.play()
}
}
Instead of Filemanager.createFile(), try using write instead.
let videoData = try Data(contentsOf: url)
try videoData.write(to: paths, options: .atomic)
Also, I recommend creating a folder first (from this answer).
extension URL {
static func createFolder(folderName: String) -> URL? {
let fileManager = FileManager.default
// Get document directory for device, this should succeed
if let documentDirectory = fileManager.urls(for: .documentDirectory,
in: .userDomainMask).first {
// Construct a URL with desired folder name
let folderURL = documentDirectory.appendingPathComponent(folderName)
// If folder URL does not exist, create it
if !fileManager.fileExists(atPath: folderURL.path) {
do {
// Attempt to create folder
try fileManager.createDirectory(atPath: folderURL.path,
withIntermediateDirectories: true,
attributes: nil)
} catch {
// Creation failed. Print error & return nil
print(error.localizedDescription)
return nil
}
}
// Folder either exists, or was created. Return URL
return folderURL
}
// Will only be called if document directory not found
return nil
}
}
Then, you can save like this:
guard let folderURL = URL.createFolder(folderName: "StoredVideos") else {
print("Can't create url")
return
}
let permanentFileURL = folderURL.appendingPathComponent(nameOfYourFile).appendingPathExtension("MOV")
let videoData = try Data(contentsOf: url)
try videoData.write(to: permanentFileURL, options: .atomic)
This will save you the hassle of NSSearchPathForDirectoriesInDomains.

how to write bytes data in file swift

data coming from server is in ex.2035bytes I want to write this data in to file I am writing but data is not showing
Alamofire.request(url , method: .post, parameters: Parameters as? [String: Any] , encoding: URLEncoding.httpBody, headers: [
"Content-Type": "application/x-www-form-urlencoded"
]).responseData{ (response) in
print(response)
print(response.result.value!)
print(response.result.description)
guard let jsonData = response.result.value ,response.result.isSuccess else {
didFail(response.result.error!)
return
}
guard let id = ApplicantModel.shared.applicationId else {
return
}
let file = "application_\(id)" //this is the file. we will write to and read from it
let documentsPath1 = NSURL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0])
//let logsPath = documentsPath1.appendingPathComponent("f")
let fileURL = documentsPath1.appendingPathComponent("file")
let data: Data = response.result.value!
// print(logsPath)
//writing
do {
try FileManager.default.createDirectory(at: documentsPath1 as URL, withIntermediateDirectories: true, attributes: nil)
//try data.write(to: fileURL!, atomically: false, encoding: .utf8)
// try data.write(to: fileURL!, options: Data.WritingOptions.atomic)
try data.write(to: fileURL!) )
}
catch {/* error handling here */}
let json = JSON(jsonData)
didFinish(json)
}
here I am creating file and writing data in to it but its not showing
You can use this function to write data. Code is self explanatory, but I tried to make it more clear.
func writeToFile(data: Data, fileName: String){
// get path of directory
guard let directory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last else {
return
}
// create file url
let fileurl = directory.appendingPathComponent("\(fileName).txt")
// if file exists then write data
if FileManager.default.fileExists(atPath: fileurl.path) {
if let fileHandle = FileHandle(forWritingAtPath: fileurl.path) {
// seekToEndOfFile, writes data at the last of file(appends not override)
fileHandle.seekToEndOfFile()
fileHandle.write(data)
fileHandle.closeFile()
}
else {
print("Can't open file to write.")
}
}
else {
// if file does not exist write data for the first time
do{
try data.write(to: fileurl, options: .atomic)
}catch {
print("Unable to write in new file.")
}
}
}
You have a problem with creating the directory and naming the file you need to change it like this
let file = "application_\(id)"
let documentsPath1 = NSURL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0])
let logsPath = documentsPath1.appendingPathComponent("file")
do
{
try FileManager.default.createDirectory(atPath: logsPath!.path, withIntermediateDirectories: true, attributes: nil)
let fileURL = logsPath?.appendingPathComponent(file)
try data.write(to: fileURL!)
}
catch let error as NSError
{
NSLog("Unable to create directory \(error.debugDescription)")
}
I think you create a wrong folder. It due to you can't save that file in your folder. You can look at my example. Which I create 1 folder to contain files.
Step1: Get document path
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
Step2: create a destination URL. Where you would like to store
let url = paths[0].appendingPathComponent(self.fileImagejpeg)
Step 3: Write data in files
try? data.write(to: url)
You can use try catch to get log when write failure

Remove all files from within documentDirectory in Swift

I am making an audio app, and the user can download files locally stored to the documentDirectory using FileManager.
Next, I'd like to allow the user to delete all files using a button. In the documentation, there is a method to remove items.
Here's my code:
#IBAction func deleteDirectoryButton(_ sender: Any) {
let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
do {
try FileManager.default.removeItem(at: documentsUrl, includingPropertiesForKeys: nil, options: [])
} catch let error {
print(error)
}
}
Unfortunately, this won't build with an error Ambiguous reference to member 'removeItem(atPath:)'.
Is there a better approach to access the documentDirectory and remove all files from the directory in one swoop?
First of all the error occurs because the signature of the API is wrong. It's just removeItem(at:) without the other parameters.
A second issue is that you are going to delete the Documents directory itself rather than the files in the directory which you are discouraged from doing that.
You have to get the contents of the directory and add a check for example to delete only MP3 files. A better solution would be to use a subfolder.
let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
do {
let fileURLs = try FileManager.default.contentsOfDirectory(at: documentsUrl,
includingPropertiesForKeys: nil,
options: .skipsHiddenFiles)
for fileURL in fileURLs where fileURL.pathExtension == "mp3" {
try FileManager.default.removeItem(at: fileURL)
}
} catch { print(error) }
Side note: It is highly recommended to use always the URL related API of FileManager.
Try this
func clearAllFiles() {
let fileManager = FileManager.default
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
print("Directory: \(paths)")
do {
let fileName = try fileManager.contentsOfDirectory(atPath: paths)
for file in fileName {
// For each file in the directory, create full path and delete the file
let filePath = URL(fileURLWithPath: paths).appendingPathComponent(file).absoluteURL
try fileManager.removeItem(at: filePath)
}
} catch let error {
print(error)
}
}
Just use code as Follow
to save AudioFile in Document Directory as
func getDocumentsDirectory() -> URL
{
//Get Basic URL
let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
/// Enter a Directory Name in which files will be saved
let dataPath1 = documentsDirectory.appendingPathComponent("folder_name_enter")
let dataPath = dataPath1.appendingPathComponent("folder inside directory if required (name)")
//Handler
do
{
try FileManager.default.createDirectory(atPath: dataPath.path, withIntermediateDirectories: true, attributes: nil)
}
catch let error as NSError
{
print("Error creating directory: \(error.localizedDescription)")
}
return dataPath
}
Delete
func clearAllFilesFromTempDirectory()
{
let fileManager = FileManager.default
let dirPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let tempDirPath = dirPath.appending("/folder_name/\(inside_directoryName)")
do {
let folderPath = tempDirPath
let paths = try fileManager.contentsOfDirectory(atPath: tempDirPath)
for path in paths
{
try fileManager.removeItem(atPath: "\(folderPath)/\(path)")
}
}
catch let error as NSError
{
print(error.localizedDescription)
}
}
Saving Method
getDocumentsDirectory().appendingPathComponent("\(audioName).wav")
Deletion Method
/// Just call
clearAllFilesFromTempDirectory
This my extension for remove all files and caches from directory.
// MARK: - FileManager extensions
extension FileManager {
/// Remove all files and caches from directory.
public static func removeAllFilesDirectory() {
let fileManager = FileManager()
let mainPaths = [
FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).map(\.path)[0],
FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).map(\.path)[0]
]
mainPaths.forEach { mainPath in
do {
let content = try fileManager.contentsOfDirectory(atPath: mainPath)
content.forEach { file in
do {
try fileManager.removeItem(atPath: URL(fileURLWithPath: mainPath).appendingPathComponent(file).path)
} catch {
// Crashlytics.crashlytics().record(error: error)
}
}
} catch {
// Crashlytics.crashlytics().record(error: error)
}
}
}
}
Swift 5
Delete the whole folder:
If you'd like to delete a whole folder you can simply do this:
func deleteFolder(_ folderName: String, completion: () -> Void) {
let fileManager = FileManager.default
let directory = fileManager.cachesDirectory().appendingPathComponent(folderName)
_ = try? fileManager.removeItem(at: directory)
completion()
}
Delete certain files based on their name:
This will loop through all the files and remove all that contain the
func removeFiles(containing: String, completion: () -> Void) {
let fileManager = FileManager.default
let directory = fileManager.cachesDirectory()
if let fileNames = try? fileManager.contentsOfDirectory(atPath: directory.path) {
for file in fileNames {
if file.contains(containing) {
let filePath = URL(fileURLWithPath: directory.path).appendingPathComponent(file).absoluteURL
_ = try? fileManager.removeItem(at: filePath)
}
}
}
completion()
}

SSZipArchive unzip from Url

I am using SSZipArchive to unzip files from a Url (http://www.colorado.edu/conflict/peace/download/peace.zip). For this I am using the function :
SSZipArchive.unzipFile(atPath: path, toDestination: documentsPath, progressHandler: {
Is it possible to extract files from Url using SSZipArchive ?
Is yes, how do I pass Url in atPath ?
You can't directly unzip without downloading the file from the URL.
This is how I do this,
func downLoad() {
let url : String = "http://www.colorado.edu/conflict/peace/download/peace.zip"
var localPath: NSURL?
Alamofire.download(.GET,url,
destination: { (temporaryURL, response) in
let directoryURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
let pathComponent = response.suggestedFilename
localPath = directoryURL.URLByAppendingPathComponent(pathComponent!)
return localPath!
})
.response { (request, response, _, error) in
SwiftEventBus.post("DownloadedSuccessfully", sender: localPath!)
}
}
After downloading the content, unzip it where you want to.
SwiftEventBus.onMainThread(self, name:"DownloadedSuccessfully")
{
result in
let resultStatus = result.object as! NSURL
guard let zipPath: String = resultStatus.path! as String else {
return
}
guard let unZipPath = unzipPath() else {
return
}
let success = SSZipArchive.unzipFileAtPath(zipPath, toDestination: unZipPath)
print(unZipPath)
if !success {
return
}
}
I unzipped the file and stored it in the document directory
func unzipPath() -> String? {
let path = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0]
let url = NSURL(fileURLWithPath: path)
do {
try NSFileManager.defaultManager().createDirectoryAtURL(url, withIntermediateDirectories: true, attributes: nil)
} catch {
return nil
}
if let path = url.path {
return path
}
return nil
}
From there you can access the data of the file. Here I used third party frameworks Alamofire and swiftEventBus. Hope this works for you.

Swift data write to Document directory maintaining directory structure

I am downloading file from firebase. let say the request url is following
social-cam-storage/albm-72/owner-2/1484043313786.jpeg
i can download the file using the following code
func downloadFile(url : String) {
let storageR = FIRStorage.storage().reference(withPath: url)
let maxSize : Int64 = 3 * 1024 * 1024 // 3MB
storageR.data(withMaxSize: maxSize) { (data, error) in
if error != nil {
print(error.debugDescription)
return
}
print(data!)
}
}
Now i need to store this data maintaining the directory structure of the url
I have tried
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
print(FileManager.default.createFile(atPath: "\(documentsURL.absoluteString)/\(url)", contents: data!, attributes: nil))
but i am getting false
so how to fix this or is there any other way to save??
Have you tried something like this? :
If you have the exact path already as a string:
try? data.write(to: URL(fileURLWithPath: path), options: [.atomic])
If you need the path there are a few methods:
func saveFile() {
let filePath = getDocumentsURL().absoluteString.appending(path)
try? data.write(to: URL(fileURLWithPath: filePath), options: [.atomic])
}
func getDocumentsURL() -> URL {
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
return documentsURL
}
You could also just try saving the filename, and then loading later when you need it:
func fileInDocumentsDirectory(_ filename: String) -> String {
let fileURL = getDocumentsURL().appendingPathComponent(filename)
return fileURL.path
}
// To save file
func saveFile(data: Data) {
let fileName:String = "createUniqueFileName"
let filePath = fileInDocumentsDirectory(fileName)
saveData(data, filePath)
}
// To load file with saved file name
func loadFile(fileName: String) {
if let loadedData = loadData(fileName) {
// Handle data however you wish
}
}
func saveData(_ data: Data, path: String ) {
try? data.write(to: URL(fileURLWithPath: path), options: [.atomic])
}
func loadData(_ path: String) -> Data? {
let data:Data? = try? Data(contentsOf: URL(fileURLWithPath: path))
return data
}
Have you tried using the built in "download to file" API in Firebase Storage?
// Create a reference to the file you want to download
let fileURL = storage.reference(withPath: url)
// Create local filesystem URL
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let fileURL = ...
// Download to the local filesystem
let downloadTask = islandRef.write(toFile: fileURL) { url, error in
if let error = error {
// Uh-oh, an error occurred!
} else {
// Local file URL is returned
}
}

Resources