I am using Alamofire to download files from the server. But i want to name it differently just like how we download the file from web and can name it as we want, same How is it possible in swift
I am using the following code:-
Alamofire.download(fileUrl, to: destination)
.downloadProgress { progress in
print("Download Progress:---------- \
(progress.fractionCompleted)")
}
.responseData { response in
print(response.request)
print(response.response)
print(response.temporaryURL)
print(response.destinationURL)
print(response.error)
}
Prefering not to use alamofire to rename or overrite files. Is there any other method
Here is the hands on function to save your Data into DocumentDirectory with the name you given. This method have one call back which will call after performing saving action, it will return the path where the image saved in directory. This function written in Swift 3.
func saveImageInDocDirectory(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) {
do {
try FileManager.default.createDirectory(at: URL(fileURLWithPath: path), withIntermediateDirectories: false, attributes: nil)
} catch {
print("Error creating images folder in Cache dir: \(error)")
}
}
if (filemgr.fileExists(atPath: path)) {
try! filemgr.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.")
}
}
}
you can call this method like,
Alamofire.download(fileUrl, to: destination)
.downloadProgress { progress in
print("Download Progress:---------- \
(progress.fractionCompleted)")
}
.responseData { response in
print(response.request)
print(response.response)
print(response.temporaryURL)
print(response.destinationURL)
print(response.error)
if let data = response.result.value {
self.saveImageInDocDirectory(data: data, fileName: "YourFile", successblock: { (path) in
print(path)
}
}
}
Thanks.
Related
I want to download the file from the URL Array and put the results stored in another Array.
Ex.
let urls = [URL1,URL2,URL3,....]
for url in urls {
AF.download(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers:
headers, interceptor: nil, to: destination).response { (responseData) in
self.urlLoad.append(responseData.fileURL!)
completion(self.urlLoad)
}
}
What I am having a problem with right now is the download and get the same result. I don't know what to do. Please guide me
You haven’t shared your destination, but the question is how that closure was defined and how you built the URL that was returned. But you want to give it a DownloadRequest.Destination closure that returns a unique path for each URL. For example, you can tell it to put the downloads in the “caches” folder like so:
let urls = [
"https://spaceflight.nasa.gov/gallery/images/apollo/apollo17/hires/s72-55482.jpg",
"https://spaceflight.nasa.gov/gallery/images/apollo/apollo10/hires/as10-34-5162.jpg",
"https://spaceflight.nasa.gov/gallery/images/apollo-soyuz/apollo-soyuz/hires/s75-33375.jpg",
"https://spaceflight.nasa.gov/gallery/images/apollo/apollo17/hires/as17-134-20380.jpg",
"https://spaceflight.nasa.gov/gallery/images/apollo/apollo17/hires/as17-140-21497.jpg",
"https://spaceflight.nasa.gov/gallery/images/apollo/apollo17/hires/as17-148-22727.jpg"
].compactMap { URL(string: $0) }
let folder = try! FileManager.default
.url(for: .cachesDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
.appendingPathComponent("images")
for url in urls {
let destination: DownloadRequest.Destination = { _, _ in
let fileURL = folder.appendingPathComponent(url.lastPathComponent)
return (fileURL, [.removePreviousFile, .createIntermediateDirectories])
}
AF.download(url, to: destination).response { responseData in
switch responseData.result {
case .success(let url):
guard let url = url else { return }
self.urlLoad.append(url)
case .failure(let error):
print(error)
}
}
}
Or, alternatively:
for url in urls {
AF.download(url) { _, _ in
(folder.appendingPathComponent(url.lastPathComponent), [.removePreviousFile, .createIntermediateDirectories])
}.response { responseData in
switch responseData.result {
case .success(let url):
guard let url = url else { return }
self.urlLoad.append(url)
case .failure(let error):
print(error)
}
}
}
First of all, after successfully download from the URL using Alamofire, I am changing the file extension to.ZIP, then getting an error while unzipping.
Not getting expected file.
let destination = DownloadRequest.suggestedDownloadDestination(for: .documentDirectory)
Alamofire.download(fileURL!, method: .get, parameters: nil, encoding: JSONEncoding.default, headers: headers, to: destination).downloadProgress(closure: { (progress) in
print(progress.completedUnitCount)
}).responseData { (responce) in
let destiUrl = responce.destinationURL
print(destiUrl!)
let newUrl = destiUrl?.deletingPathExtension().appendingPathExtension("zip")
do {
try FileManager.default.copyItem(at: destiUrl!, to: newUrl!)
let unzipDirectory = try Zip.quickUnzipFile(newUrl!)
print(unzipDirectory.absoluteString)
}
catch let error as NSError{
print(error)
}
}
File URL after successful download-->
file:///var/mobile/Containers/Data/Application/9D96958C-903E-4693-9965-6FB919BB24F1/Documents/'87dc4a8ddce24cf9ad35a251d6a98195.hub'
File URL after converting to .zip
file:///var/mobile/Containers/Data/Application/9D96958C-903E-4693-9965-6FB919BB24F1/Documents/'87dc4a8ddce24cf9ad35a251d6a98195.zip
Final url after unzipping
file:///var/mobile/Containers/Data/Application/9D96958C-903E-4693-9965-6FB919BB24F1/Documents/'87dc4a8ddce24cf9ad35a251d6a98195/
Actual result should be audio file.
Tried replacing the name of the file at the time of successfully download using below code. -->
func saveFileInDocDirectory(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.")
}
}
}
And after that unzipped using SSZipArchive library in Alamofire download function -->
Alamofire.download(fileURL!, method: .get, parameters: nil, encoding: JSONEncoding.default, headers: headers, to: destination).downloadProgress(closure: { (progress) in
print(progress.completedUnitCount)
}).responseData { (responce) in
let destiUrl = responce.destinationURL
print(destiUrl!)
let name = destiUrl?.deletingPathExtension().lastPathComponent
self.saveFileInDocDirectory(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)
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
player = AVQueuePlayer(url: destinationUrl)
player.play()
}
} catch let error as NSError{
print(error)
}
})
}
func downLoad(fileName:String) {
let urlString : String = "\(myurl)\(fileName)"
var localPath: NSURL?
let destination = DownloadRequest.suggestedDownloadDestination(for: .documentDirectory)
Alamofire.download(urlString, method: .get, encoding: JSONEncoding.default, to: destination)
.downloadProgress(queue: DispatchQueue.global(qos: .utility)) { progress in
print("Progress: \(progress.fractionCompleted)")
}
.validate { request, response, temporaryURL, destinationURL in
// Custom evaluation closure now includes file URLs (allows you to parse out error messages if necessary)
return .success
}
.responseJSON { response in
debugPrint(response)
print(response.destinationURL?.path)
print(response.destinationURL?.absoluteString)
let unzipDirectory = self.unzipPath(fileURL:fileName)
let success = SSZipArchive.unzipFile(atPath: (response.destinationURL?.path)!, toDestination: unzipDirectory!)
print(success)
if !success {
return
}
}
}
func unzipPath(fileName:String) -> String? {
let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
let url = NSURL(fileURLWithPath: path)
let pathComponent = url.appendingPathComponent("test\(fileName)")
do {
try FileManager.default.createDirectory(at: pathComponent!, withIntermediateDirectories: true, attributes: nil)
} catch {
return nil
}
return pathComponent?.absoluteString
}
i get right path in response.destinationURL
but success is false
i tried atPath : to response.destinationURL?.path and
response.destinationURL?.absoluteString
but failed too
What i am doing wrong
destinationURL?.path return this
Optional("/Users/MyUser/Library/Developer/CoreSimulator/Devices/3FBAD207-E5AB-4FC1-8199-2269A1249D97/data/Containers/Data/Application/CB1C2EF5-3100-430B-B869-774C09B8EA7F/Documents/testFile.zip")
response.destinationURL?.absoluteString
return this
Optional("file:///Users/MyUser/Library/Developer/CoreSimulator/Devices/3FBAD207-E5AB-4FC1-8199-2269A1249D97/data/Containers/Data/Application/CB1C2EF5-3100-430B-B869-774C09B8EA7F/Documents/testFile.zip")
i think this is correct URL
why failed unzip?
By looking at your code, the path you are using for the source is perfect.
For the destination path, try updating it to
func unzipPath(fileName:String) -> String? {
let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString
let pathWithComponent = path.appendingPathComponent("test\(fileName)")
do {
try FileManager.default.createDirectory(atPath: pathWithComponent, withIntermediateDirectories: true, attributes: nil)
} catch {
return nil
}
return pathWithComponent
}
Try and share the results.
I download a zip file with Alamofire4 and unzip it with SSZipArchive but the unzip does not work. I am not sure if the path of the downloaded file is good with Alamofire.
Here is the code:
let destination: DownloadRequest.DownloadFileDestination = { _, _ in
var documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
return (documentsURL, [.removePreviousFile])
}
Alamofire.download(urlString, method: .get, parameters: parameters, encoding: JSONEncoding.default, to: destination)
.response{ response in
if response.error == nil {
let filename = response.response?.suggestedFilename
var folderDestination=response.destinationURL?.path
folderDestination=folderDestination?.appending("/\(nameCategory)")
archiveToUnzip=(folderDestination?.appending("/\(filename!)"))!
//unzip
let successUnZip=SSZipArchive.unzipFile(atPath: archiveToUnzip, toDestination:folderDestination!)
if !successUnZip {
SpeedLog.print("Problem unzip")
}
}
}
It displays "Problem unzip", so am I wrong in the path to the zip file?
Before unzipping try to check that all paths were correct:
guard let zipPath = (folderDestination?.appending("/\(filename!)"))! else {
print("Error: zipPath are not correct: \(zipPath)")
return
}
guard let unzipPath = folderDestination! else {
print("Error: unzipPath are not correct: \(unzipPath)")
return
}
let success = SSZipArchive.unzipFile(atPath: zipPath, toDestination: unzipPath)
if !success {
print("Error: unzipFile operation failed")
return
}
Simply you can't create folder name by appending the path, You need to create folder separately. Here is the code try this!
let filename = response.response?.suggestedFilename
var folderDestination=response.destinationURL?.path
folderDestination=folderDestination?.appending("/\(nameCategory)")
try! FileManager.default.createDirectory(at: folderDestination!, withIntermediateDirectories: false, attributes: nil)
archiveToUnzip=(folderDestination?.appending("/\(filename!)"))!
//unzip
let successUnZip=SSZipArchive.unzipFile(atPath: archiveToUnzip,toDestination:folderDestination!)
How can I check if a given file has been already downloaded before re-downloading it by using Alamofire? I'm using suggestedDownloadDestination so Alamofire will automatically choose the name of the file and save it in the choosen directory, for example the .CachesDirectory. The problem is that the value given by suggestedDownloadDestination is of type DownloadFileDestination which will return a NSURL only by calling him with the request's response, but in this way I could not ever know the file path without performing a request before.
This is the code I currently use to download a file with Alamofire:
Alamofire.download(.GET, downloadLink, destination: destination).progress {
bytesRead, totalBytesRead, totalBytesExpectedToRead in
}.response {
request, response, data, error in
guard error == nil else {
return
}
// This will give me the file path but we're already in a Request!
print("\(destination(NSURL(string: "")!, response!))")
}
What am I missing?
Not sure if you figured this out yet, but you can create an extension over Alamofire.DownloadRequest like:
extension Alamofire.DownloadRequest {
open class func suggestedDownloadDestination(
for directory: FileManager.SearchPathDirectory = .documentDirectory,
in domain: FileManager.SearchPathDomainMask = .userDomainMask,
with options: DownloadOptions)
-> DownloadFileDestination
{
return { temporaryURL, response in
let destination = DownloadRequest.suggestedDownloadDestination(for: directory, in: domain)(temporaryURL, response)
return (destination.destinationURL, options)
}
}
}
Now you can specify in the options parameter if you want the file to be overwritten:
let destination = DownloadRequest.suggestedDownloadDestination(for: .cachesDirectory,
in: .userDomainMask,
with: [DownloadRequest.DownloadOptions.removePreviousFile])
Here is the solution which I used
Download a file
check if it exist if so just return the path otherwise
func downloadDocumentFile(filePath: String,onDownloadProgress: #escaping(_ progress: Double) -> Void,onError: #escaping(_ errorMessage: String) -> Void,onSuccess: #escaping(_ destinationUrl: URL) -> Void){
guard let url = URL(string: filePath) else {
onError("Couldn't create url from passed file path")
assertionFailure()
return
}
let destination = DownloadRequest.suggestedDownloadDestination(for: .documentDirectory, in: .userDomainMask)
Alamofire.download(url, to: destination)
.downloadProgress { (progress) in
onDownloadProgress(progress.fractionCompleted)
}
.responseData(queue: .main) { (response) in
switch response.result {
case .success:
if let destinationUrl = response.destinationURL {
onSuccess(destinationUrl)
}else {
onError("Couldn't get destination url")
assertionFailure()
}
case .failure(let error):
// check if file exists before
if let destinationURL = response.destinationURL {
if FileManager.default.fileExists(atPath: destinationURL.path){
// File exists, so no need to override it. simply return the path.
onSuccess(destinationURL)
print()
}else {
onError(error.localizedDescription)
assertionFailure()
}
}else {
onError(error.localizedDescription)
assertionFailure()
}
}
}
}