//生成一个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
}