Swift用URLSession實(shí)現(xiàn)文件的下載

最近根據(jù)URLSession 實(shí)現(xiàn)文件的下載,簡(jiǎn)單地封裝了一下注釋很詳細(xì),這里不再過多的贅述,喜歡的可以看看.

  • 1 FileTool.swift 實(shí)現(xiàn)獲取文件的大小/移動(dòng)文件/文件是否存在等等的判斷
  • 2 DownLoader.swift 是下載文件的主類
  • 3在Controller中創(chuàng)建DownLoader對(duì)象,即可使用

??

首先是 下載的類 DownLoader.swift

import UIKit

private let kCachePath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.cachesDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).first
private let kTempPath = NSTemporaryDirectory()

class DownLoader: NSObject  {

    fileprivate var downLoadedPath : String?
    fileprivate var downLoadingPath : String?
    fileprivate var outputStream : OutputStream?
    fileprivate var tmpSize : CLongLong = 0
    fileprivate var totalSize : CLongLong = 0
    
    
    fileprivate lazy var session : URLSession  = {
        
        let config = URLSessionConfiguration.default
        let session = URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue.main)
        return session
        
    }()
    
    func downLoader(url : NSURL) {
        
        let fileName = url.lastPathComponent

        guard url.lastPathComponent != nil else {
            print("url有問題")
            return
        }
        
        self.downLoadingPath = kTempPath + "/" + fileName!
        self.downLoadedPath = kCachePath! + "/" + fileName!
        
        //檢查當(dāng)前路徑是否已經(jīng)下載了該文件
        if FileTool.fileExists(filePath: self.downLoadedPath!) {
            print("文件以及下載完成")
            return
        }
        
        print(self.downLoadingPath ?? "")
        
        //如果沒有下載完成 就看是否有臨時(shí)文件
        if !FileTool.fileExists(filePath: self.downLoadingPath!) {
            //不存在的話 直接開始下載
            self.downLoadWithURL(url as URL, 0)
            
            return;
        }
        
        
        //已經(jīng)下載了的 先計(jì)算 下載的大小,然后繼續(xù)下載
        tmpSize = FileTool.fileSize(self.downLoadingPath!)
        self.downLoadWithURL(url as URL, tmpSize)
        
    }
    
    
    // MARK:- 開始請(qǐng)求資源
    func downLoadWithURL(_ url : URL, _ offset : CLongLong) {
        
        var request = NSURLRequest(url: url, cachePolicy: NSURLRequest.CachePolicy.reloadIgnoringCacheData, timeoutInterval: 0) as URLRequest
        
        request.setValue("bytes=%lld-", forHTTPHeaderField: "Range")
        
       let dataTask = self.session.dataTask(with: request)
        
        dataTask.resume()
    }
    
    
}


extension DownLoader : URLSessionDataDelegate {
    
    func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Swift.Void){
        
        print(response)
        let resp = response as! HTTPURLResponse
//        self.totalSize = resp.allHeaderFields["Content-Length"] as! CLongLong?
        
//        self.totalSize = String(resp.allHeaderFields["Content-Length"]).components(separatedBy: "/").last).CLongLong
        
        let string = resp.allHeaderFields["Content-Length"] as! String
        
        let stri : String = string.components(separatedBy: "/").last!
                
        self.totalSize = CLongLong(stri)!
        
        
        
       // 比對(duì)本地大小, 和 總大小
        if (self.tmpSize == self.totalSize) {
            
            // 1. 移動(dòng)到下載完成文件夾
            print("移動(dòng)文件到下載完成")
            FileTool.moveFile(self.downLoadingPath!, self.downLoadedPath!)
            // 2. 取消本次請(qǐng)求
            completionHandler(URLSession.ResponseDisposition.cancel);
            return;
        }
        
        if (self.tmpSize > self.totalSize) {
            
            // 1. 刪除臨時(shí)緩存
            print("刪除臨時(shí)緩存")
            FileTool.removeFile(self.downLoadingPath!)
            
            
            // 2. 從0 開始下載
            print("重新開始下載")
            self.downLoader(url: resp.url! as NSURL)
            //             [self downLoadWithURL:response.URL offset:0];
            // 3. 取消請(qǐng)求
            completionHandler(URLSession.ResponseDisposition.cancel);
            
            return;
            
        }
        
        
        
        // 繼續(xù)接受數(shù)據(jù)
        // 確定開始下載數(shù)據(jù)
        self.outputStream = OutputStream(toFileAtPath: self.downLoadingPath!, append: true)
        
        self.outputStream?.open()
        completionHandler(URLSession.ResponseDisposition.allow);
        
        
        
    }
    
    func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data){
        
        var buffer = [UInt8](repeating: 0, count: data.count)
        data.copyBytes(to: &buffer, count: data.count)
        
        self.outputStream?.write(buffer, maxLength: data.count)

        
//        let uint8Ptr = UnsafeMutablePointer<UInt8>.allocate(capacity: data.count)
//        uint8Ptr.initialize(from: data)
//        let rawPtr = UnsafeRawPointer(uint8Ptr)
//        self.outputStream?.write(rawPtr, maxLength: da.length)

    }
    
    func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?){
        
        print("請(qǐng)求完成")
        
        
        if (error == nil) {
            
            // 不一定是成功
            // 數(shù)據(jù)是肯定可以請(qǐng)求完畢
            // 判斷, 本地緩存 == 文件總大小 {filename: filesize: md5:xxx}
            // 如果等于 => 驗(yàn)證, 是否文件完整(file md5 )
           
        }else {
            print("有問題")
        }
      
        self.outputStream?.close()      
        
    }
  
}

其次是文件的工具類 FileTool.swift

import UIKit

class FileTool: NSObject {

    
    // MARK:- 判斷文件目錄是否存在
    class func fileExists(filePath : String) -> Bool {
        
        if (filePath.characters.count == 0) {
            return false
        }
        return FileManager.default.fileExists(atPath: filePath)
    }
    
    // MARK:- 獲取文件的大小
    class func  fileSize(_ filePath : String) ->CLongLong{
    
        if !self.fileExists(filePath: filePath) {
            return 0
        }
        
        let fileInfo = try! FileManager.default.attributesOfItem(atPath: filePath)
        
        return fileInfo[FileAttributeKey.size] as! CLongLong
        
    }
    
    // MARK:- 移動(dòng)文件
    class func moveFile(_ fromPath : String , _ toPath : String){
        
        if self.fileSize(fromPath)  == 0 {
            return
        }
        try! FileManager.default.moveItem(atPath: fromPath, toPath: toPath)
    }
    
    class func removeFile(_ filePath : String){
       try! FileManager.default.removeItem(atPath: filePath)
    }
  
}

使用很簡(jiǎn)單

    fileprivate var downLoader = DownLoader()

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        
        let url = NSURL(string: "http://free2.macx.cn:8281/tools/photo/SnapNDragPro418.dmg")
        
        self.downLoader.downLoader(url: url!)
        
    }

<附上鏈接地址??>
下載鏈接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,229評(píng)論 4 61
  • 每年農(nóng)歷五月初五為端午節(jié),是中國民間的傳統(tǒng)節(jié)日,又稱端陽節(jié),重五節(jié)。端午節(jié)流行于漢、壯、布依、侗、土家、仡佬等名族...
    senny1978閱讀 237評(píng)論 0 1
  • 過程重要還是結(jié)果重要?規(guī)劃重要還是機(jī)會(huì)重要?工作重要還是親朋好友重要? 如果你說都重要,肯定有人會(huì)接著問:“哪個(gè)更...
    楚丹丹閱讀 549評(píng)論 0 2