如何在swift下载文件?

我刚刚开始学习iOS的苹果swift编程来自android。 我现在基本上可以读取和操作swift代码,并且学习了一些在iOS Swift编程中使用的常用类,但仍然对语法和一切都有些困惑。

我正试图下载文件。 就像我们刚刚说的,来自这个URL

var url = "myfile.html" 

在button点击。 也许还有视觉上的进步

通过在这里searchstackoverflow,我偶然发现了Alamofire。 我可能会尝试,但我不知道这是否是我做这件事的最好方法。

所以,我想问一下我的select(iOS7和iOS8)在实现我的目标方面是什么以及有什么。 此外,利弊将是可怕的!

没有Alamofire的示例下载器类:

 class Downloader { class func load(URL: NSURL) { let sessionConfig = NSURLSessionConfiguration.defaultSessionConfiguration() let session = NSURLSession(configuration: sessionConfig, delegate: nil, delegateQueue: nil) let request = NSMutableURLRequest(URL: URL) request.HTTPMethod = "GET" let task = session.dataTaskWithRequest(request, completionHandler: { (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void in if (error == nil) { // Success let statusCode = (response as NSHTTPURLResponse).statusCode println("Success: \(statusCode)") // This is your file-variable: // data } else { // Failure println("Failure: %@", error.localizedDescription); } }) task.resume() } } 

这是如何在你自己的代码中使用它:

 class Foo { func bar() { if var URL = NSURL(string: "myfile.html") { Downloader.load(URL) } } } 

Swift 3版本

另外请注意在磁盘上而不是在内存中下载大文件。 请参阅downloadTask:

 class Downloader { class func load(url: URL, to localUrl: URL, completion: @escaping () -> ()) { let sessionConfig = URLSessionConfiguration.default let session = URLSession(configuration: sessionConfig) let request = try! URLRequest(url: url, method: .get) let task = session.downloadTask(with: request) { (tempLocalUrl, response, error) in if let tempLocalUrl = tempLocalUrl, error == nil { // Success if let statusCode = (response as? HTTPURLResponse)?.statusCode { print("Success: \(statusCode)") } do { try FileManager.default.copyItem(at: tempLocalUrl, to: localUrl) completion() } catch (let writeError) { print("error writing file \(localUrl) : \(writeError)") } } else { print("Failure: %@", error?.localizedDescription); } } task.resume() } } 

以下是一个显示如何执行同步和asynchronous的示例。

 import Foundation class HttpDownloader { class func loadFileSync(url: NSURL, completion:(path:String, error:NSError!) -> Void) { let documentsUrl = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first as! NSURL let destinationUrl = documentsUrl.URLByAppendingPathComponent(url.lastPathComponent!) if NSFileManager().fileExistsAtPath(destinationUrl.path!) { println("file already exists [\(destinationUrl.path!)]") completion(path: destinationUrl.path!, error:nil) } else if let dataFromURL = NSData(contentsOfURL: url){ if dataFromURL.writeToURL(destinationUrl, atomically: true) { println("file saved [\(destinationUrl.path!)]") completion(path: destinationUrl.path!, error:nil) } else { println("error saving file") let error = NSError(domain:"Error saving file", code:1001, userInfo:nil) completion(path: destinationUrl.path!, error:error) } } else { let error = NSError(domain:"Error downloading file", code:1002, userInfo:nil) completion(path: destinationUrl.path!, error:error) } } class func loadFileAsync(url: NSURL, completion:(path:String, error:NSError!) -> Void) { let documentsUrl = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first as! NSURL let destinationUrl = documentsUrl.URLByAppendingPathComponent(url.lastPathComponent!) if NSFileManager().fileExistsAtPath(destinationUrl.path!) { println("file already exists [\(destinationUrl.path!)]") completion(path: destinationUrl.path!, error:nil) } else { let sessionConfig = NSURLSessionConfiguration.defaultSessionConfiguration() let session = NSURLSession(configuration: sessionConfig, delegate: nil, delegateQueue: nil) let request = NSMutableURLRequest(URL: url) request.HTTPMethod = "GET" let task = session.dataTaskWithRequest(request, completionHandler: { (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void in if (error == nil) { if let response = response as? NSHTTPURLResponse { println("response=\(response)") if response.statusCode == 200 { if data.writeToURL(destinationUrl, atomically: true) { println("file saved [\(destinationUrl.path!)]") completion(path: destinationUrl.path!, error:error) } else { println("error saving file") let error = NSError(domain:"Error saving file", code:1001, userInfo:nil) completion(path: destinationUrl.path!, error:error) } } } } else { println("Failure: \(error.localizedDescription)"); completion(path: destinationUrl.path!, error:error) } }) task.resume() } } } 

以下是如何在你的代码中使用它:

 let url = NSURL(string: "myfile.html") HttpDownloader.loadFileAsync(url, completion:{(path:String, error:NSError!) in println("pdf downloaded to: \(path)") }) 

只要您的应用程序处于前台,Devran's和djunod的解决scheme正在运行。 如果在下载过程中切换到另一个应用程序,则失败。 我的文件大小约为10 MB,需要一段时间才能下载。 所以我需要我的下载function,即使当应用程序进入后台。

请注意,我在“function”中打开了“背景模式/背景获取”。

由于completionhandler不被支持,所以解决scheme没有被封装。 对于那个很抱歉。

–Swift 2.3–

 import Foundation class Downloader : NSObject, NSURLSessionDownloadDelegate { var url : NSURL? // will be used to do whatever is needed once download is complete var yourOwnObject : NSObject? init(yourOwnObject : NSObject) { self.yourOwnObject = yourOwnObject } //is called once the download is complete func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL) { //copy downloaded data to your documents directory with same names as source file let documentsUrl = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first let destinationUrl = documentsUrl!.URLByAppendingPathComponent(url!.lastPathComponent!) let dataFromURL = NSData(contentsOfURL: location) dataFromURL?.writeToURL(destinationUrl, atomically: true) //now it is time to do what is needed to be done after the download yourOwnObject!.callWhatIsNeeded() } //this is to track progress func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { } // if there is an error during download this will be called func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) { if(error != nil) { //handle the error print("Download completed with error: \(error!.localizedDescription)"); } } //method to be called to download func download(url: NSURL) { self.url = url //download identifier can be customized. I used the "ulr.absoluteString" let sessionConfig = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier(url.absoluteString) let session = NSURLSession(configuration: sessionConfig, delegate: self, delegateQueue: nil) let task = session.downloadTaskWithURL(url) task.resume() } } 

这里是如何调用–Swift 2.3 –

  let url = NSURL(string: "http://company.com/file.txt") Downloader(yourOwnObject).download(url!) 

–Swift 3–

 class Downloader : NSObject, URLSessionDownloadDelegate { var url : URL? // will be used to do whatever is needed once download is complete var yourOwnObject : NSObject? init(_ yourOwnObject : NSObject) { self.yourOwnObject = yourOwnObject } //is called once the download is complete func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { //copy downloaded data to your documents directory with same names as source file let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first let destinationUrl = documentsUrl!.appendingPathComponent(url!.lastPathComponent) let dataFromURL = NSData(contentsOf: location) dataFromURL?.write(to: destinationUrl, atomically: true) //now it is time to do what is needed to be done after the download yourOwnObject!.callWhatIsNeeded() } //this is to track progress private func URLSession(session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { } // if there is an error during download this will be called func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { if(error != nil) { //handle the error print("Download completed with error: \(error!.localizedDescription)"); } } //method to be called to download func download(url: URL) { self.url = url //download identifier can be customized. I used the "ulr.absoluteString" let sessionConfig = URLSessionConfiguration.background(withIdentifier: url.absoluteString) let session = Foundation.URLSession(configuration: sessionConfig, delegate: self, delegateQueue: nil) let task = session.downloadTask(with: url) task.resume() }} 

这里是如何打电话–Swift 3–

  let url = URL(string: "http://company.com/file.txt") Downloader(yourOwnObject).download(url!) 

如果你只需要将文本文件下载到String你可以用这个简单的方法, Swift 3

 let list = try? String(contentsOf: URL(string: "https://example.com/file.txt")!) 

如果你想要非可选的结果或error handling:

 do { let list = try String(contentsOf: URL(string: "https://example.com/file.txt")!) } catch { // Handle error here } 

您应该知道networking操作可能需要一些时间,为了防止它在主线程中运行并locking您的UI,您可能需要asynchronous执行代码,例如:

 DispatchQueue.global().async { let list = try? String(contentsOf: URL(string: "https://example.com/file.txt")!) } 

试试这个代码只Swift 3.0首先创buildNS对象文件复制这个代码在创build的文件

 import UIKit class Downloader : NSObject, URLSessionDownloadDelegate { var url : URL? // will be used to do whatever is needed once download is complete var obj1 : NSObject? init(_ obj1 : NSObject) { self.obj1 = obj1 } //is called once the download is complete func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { //copy downloaded data to your documents directory with same names as source file let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first let destinationUrl = documentsUrl!.appendingPathComponent(url!.lastPathComponent) let dataFromURL = NSData(contentsOf: location) dataFromURL?.write(to: destinationUrl, atomically: true) //now it is time to do what is needed to be done after the download //obj1!.callWhatIsNeeded() } //this is to track progress private func URLSession(session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { } // if there is an error during download this will be called func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { if(error != nil) { //handle the error print("Download completed with error: \(error!.localizedDescription)"); } } //method to be called to download func download(url: URL) { self.url = url //download identifier can be customized. I used the "ulr.absoluteString" let sessionConfig = URLSessionConfiguration.background(withIdentifier: url.absoluteString) let session = Foundation.URLSession(configuration: sessionConfig, delegate: self, delegateQueue: nil) let task = session.downloadTask(with: url) task.resume() }} 

然后复制下面的代码并把代码放在你想要下载的文件

  object = "myfile.html" let url1 = URL(string: object!) Downloader(url1! as NSObject).download(url: url1!) 

Swift 3

你想通过咬下载文件咬合并显示正在进行的视图,所以你想试试这个代码

 import UIKit class ViewController: UIViewController,URLSessionDownloadDelegate,UIDocumentInteractionControllerDelegate { @IBOutlet weak var img: UIImageView! @IBOutlet weak var btndown: UIButton! var urlLink: URL! var defaultSession: URLSession! var downloadTask: URLSessionDownloadTask! //var backgroundSession: URLSession! @IBOutlet weak var progress: UIProgressView! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. let backgroundSessionConfiguration = URLSessionConfiguration.background(withIdentifier: "backgroundSession") defaultSession = Foundation.URLSession(configuration: backgroundSessionConfiguration, delegate: self, delegateQueue: OperationQueue.main) progress.setProgress(0.0, animated: false) } func startDownloading () { let url = URL(string: "c_book/thecbook.pdf")! downloadTask = defaultSession.downloadTask(with: url) downloadTask.resume() } @IBAction func btndown(_ sender: UIButton) { startDownloading() } func showFileWithPath(path: String){ let isFileFound:Bool? = FileManager.default.fileExists(atPath: path) if isFileFound == true{ let viewer = UIDocumentInteractionController(url: URL(fileURLWithPath: path)) viewer.delegate = self viewer.presentPreview(animated: true) } } // MARK:- URLSessionDownloadDelegate func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { print(downloadTask) print("File download succesfully") let path = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true) let documentDirectoryPath:String = path[0] let fileManager = FileManager() let destinationURLForFile = URL(fileURLWithPath: documentDirectoryPath.appendingFormat("/file.pdf")) if fileManager.fileExists(atPath: destinationURLForFile.path){ showFileWithPath(path: destinationURLForFile.path) print(destinationURLForFile.path) } else{ do { try fileManager.moveItem(at: location, to: destinationURLForFile) // show file showFileWithPath(path: destinationURLForFile.path) }catch{ print("An error occurred while moving file to destination url") } } } func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { progress.setProgress(Float(totalBytesWritten)/Float(totalBytesExpectedToWrite), animated: true) } func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { downloadTask = nil progress.setProgress(0.0, animated: true) if (error != nil) { print("didCompleteWithError \(error?.localizedDescription ?? "no value")") } else { print("The task finished successfully") } } func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController { return self } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } } 

在您的应用程序中使用此代码您要自动下载文件目录中的文件目录

这段代码100%正常工作

Swift 3

 class ViewController: UIViewController { var urlLink: URL! var defaultSession: URLSession! var downloadTask: URLSessionDownloadTask! } // MARK: Button Pressed @IBAction func btnDownloadPressed(_ sender: UIButton) { let urlLink1 = URL.init(string: "QRCodeReader-master.zip") startDownloading(url: urlLink!) } @IBAction func btnResumePressed(_ sender: UIButton) { downloadTask.resume() } @IBAction func btnStopPressed(_ sender: UIButton) { downloadTask.cancel() } @IBAction func btnPausePressed(_ sender: UIButton) { downloadTask.suspend() } func startDownloading (url:URL) { let backgroundSessionConfiguration = URLSessionConfiguration.background(withIdentifier: "backgroundSession") defaultSession = Foundation.URLSession(configuration: backgroundSessionConfiguration, delegate: self, delegateQueue: OperationQueue.main) downloadProgress.setProgress(0.0, animated: false) downloadTask = defaultSession.downloadTask(with: urlLink) downloadTask.resume() } // MARK:- URLSessionDownloadDelegate func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { print("File download succesfully") } func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { downloadProgress.setProgress(Float(totalBytesWritten)/Float(totalBytesExpectedToWrite), animated: true) } func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { downloadTask = nil downloadProgress.setProgress(0.0, animated: true) if (error != nil) { print("didCompleteWithError \(error?.localizedDescription)") } else { print("The task finished successfully") } } 

使用URLSessionDownloadTask在后台下载文件,即使应用程序被终止,它们也可以完成。

有关更多信息,请参阅

https://www.ralfebert.de/snippets/ios/urlsession-background-downloads/

它还显示了如何实现并行运行的多个任务的进度监控: