天天看點

iOS 檔案下載下傳與檢視

//生成一個downloadTask
        let config = URLSessionConfiguration.default
        let session = URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue())
        self.session = session
        let dataTask = session.downloadTask(with: request)
    // 開始請求
        dataTask.resume()
           

下載下傳的網絡請求并不難,還可以擷取下載下傳進度,在完成的時候拿到回調一定要提前移出來,不然系統會自動銷毀

func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask,
                    didWriteData bytesWritten: Int64,
                    totalBytesWritten: Int64,
                    totalBytesExpectedToWrite: Int64) {
        
        //擷取進度
        let written = (Float)(totalBytesWritten)
        let total = (Float)(totalBytesExpectedToWrite)
        let pro = written/total
        if let downLoadProgress = downLoadProgress {
            downLoadProgress(pro)
        }
    }
           
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
        if let completionHandler = completionHandlerBlock {
            var tempError: Error?
            do {
                try FileManager.default.moveItem(atPath: location.path, toPath: tempPath ?? downloadTask.response?.suggestedFilename ?? "*.text")
            } catch {
                tempError = error
            }
            //完成任務,
            session.finishTasksAndInvalidate()
            //清空Session
            self.session = nil
            completionHandler(location, tempError)
        }
    }
           

下載下傳下來并不難,剩下的是我們需要做一個存儲,我是根據背景的ID來判斷檔案的唯一性,如果一個檔案多次接收,隻要檔案ID一樣,就可以直下載下傳一次,當然檔案是否真的是同一個檔案是要根據檔案的 hash值等操作來判斷的,也許同名但内容有改變,也有内容一樣隻是重命名了,具體并沒有在移動端實作,是以我并沒有深入研究,後端會判斷好,反給我檔案的ID,ID一樣的我就認為是同一個檔案就可以了

存儲的時候,用ID 然後MD5 加密是最簡單和直覺來判斷是否存在的命名方式了

下面是實作方式:

lazy var tempDirectory: String = {
        let tempPath = NSTemporaryDirectory()
        return tempPath
    }()

lazy var cacheDirectory: String = {
        let cache = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.cachesDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
        let cachePath = cache[0]
        return cachePath
    }()

// 檔案存儲路徑 需要拼接檔案名
    lazy var fileCachePath: String = {
        let directoryPath = cacheDirectory.appending("/APPName")
        if !FileManager.default.fileExists(atPath: directoryPath) {
            try? FileManager.default.createDirectory(atPath: directoryPath, withIntermediateDirectories: true, attributes: nil)
        }
        return directoryPath
    }()
    
    // 判斷檔案是否存在
    class func judgeFileIsExist(_ filePath: String) -> Bool {
        return FileManager.default.fileExists(atPath: filePath)
    }
    
// MARK: ...移動檔案
    class func moveFile(_ fromPath: String, _ toPath: String) {
        if self.getFileSizeWithFileName(fromPath)  == 0 {
            return
        }
        try? FileManager.default.moveItem(atPath: fromPath, toPath: toPath)
    }
    // 建立檔案
    class func creatFile(_ filePath: String, isDirectories: Bool = false) {
        if !FileManager.default.fileExists(atPath: filePath) {
            try? FileManager.default.createDirectory(atPath: filePath, withIntermediateDirectories: isDirectories, attributes: nil)
        }
    }
    
    // 删除檔案
    class func deleteFile(_ filePath: String) {
        if FileManager.default.fileExists(atPath: filePath) {
            do {
                try FileManager.default.removeItem(atPath: filePath)
            } catch {
                debugPrint("\(error)")
            }
        }
    }
    
    // 計算檔案大小
    class func getFileSizeWithFileName(_ path: String) -> UInt64 {
        // 1.檔案總大小
        var totalSize: UInt64 = 0
        // 2.建立檔案管理者
        let fileManager = FileManager.default
        // 3.判斷檔案存不存在以及是否是檔案夾
        var isDirectory: ObjCBool = ObjCBool(false)
        let isFileExist = fileManager.fileExists(atPath: path, isDirectory: &isDirectory)
        if !isFileExist {
            return totalSize
        } // 檔案不存在
        if (isDirectory).boolValue { // 是檔案夾
            guard let subPaths = fileManager.subpaths(atPath: path)  else {
                return totalSize
            }
            for subPath in subPaths {
                let filePath = path.appendingFormat("/%@", subPath)
                var isDirectory: ObjCBool = ObjCBool(false)
                let isExistFile = fileManager.fileExists(atPath: filePath, isDirectory: &isDirectory)
                if !isDirectory.boolValue && isExistFile && !filePath.contains("DS") {
                    do {
                        if let attr: NSDictionary = try fileManager.attributesOfItem(atPath: path) as NSDictionary? {
                            totalSize += attr.fileSize()
                        }
                    } catch {
                        debugPrint("Error: \(error)")
                    }
                }
            }
        } else { // 不是檔案夾
            do {
                if let attr: NSDictionary = try fileManager.attributesOfItem(atPath: path) as NSDictionary? {
                    totalSize += attr.fileSize()
                }
            } catch {
                debugPrint("Error: \(error)")
            }
        }
        
        return totalSize
    }
           

這樣就封裝好了一個工具類,使用的時候調用這個工具類就可以了

/**
 *  判斷檔案是否存在,判斷是否可以下載下傳(檔案不存在說明可以下載下傳,因為下面的下載下傳
 *  是存在臨時檔案的,下載下傳好了才存到真正的路徑(是以不需要去判斷檔案的大小)
 */
    func judgeFileIsExist(with content: MessageContent) -> Bool {
        let fileName = getFileName(fileId: content.fileId, fileType: content.fileType)
        let filePath =  DiskCacheTool.shared.fileCachePath + "/" + fileName
        return DiskCacheTool.judgeFileIsExist(filePath)
    }


func getFileName(fileId: Int64?, fileType: String?) -> String {
        let idString = String(format: "%d", fileId ?? "")
        let fileName = String(format: "%@.%@", idString.MD5, fileType?.lowercased() ?? "")
        return fileName
    }