• 1 FileTool.swift 实现获取文件的大小/移动文件/文件是否存在等等的判断
    • 2 DownLoader.swift 是下载文件的主类
    • 3在Controller中创建DownLoader对象,即可使用

    首先是 下载的类 DownLoader.swift

    1. import UIKit
    2. private let kCachePath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.cachesDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).first
    3. private let kTempPath = NSTemporaryDirectory()
    4. class DownLoader: NSObject {
    5. fileprivate var downLoadedPath : String?
    6. fileprivate var downLoadingPath : String?
    7. fileprivate var outputStream : OutputStream?
    8. fileprivate var tmpSize : CLongLong = 0
    9. fileprivate var totalSize : CLongLong = 0
    10. fileprivate lazy var session : URLSession = {
    11. let config = URLSessionConfiguration.default
    12. let session = URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue.main)
    13. return session
    14. }()
    15. func downLoader(url : NSURL) {
    16. let fileName = url.lastPathComponent
    17. guard url.lastPathComponent != nil else {
    18. print("url有问题")
    19. return
    20. }
    21. self.downLoadingPath = kTempPath + "/" + fileName!
    22. self.downLoadedPath = kCachePath! + "/" + fileName!
    23. //检查当前路径是否已经下载了该文件
    24. if FileTool.fileExists(filePath: self.downLoadedPath!) {
    25. print("文件以及下载完成")
    26. return
    27. }
    28. print(self.downLoadingPath ?? "")
    29. //如果没有下载完成 就看是否有临时文件
    30. if !FileTool.fileExists(filePath: self.downLoadingPath!) {
    31. //不存在的话 直接开始下载
    32. self.downLoadWithURL(url as URL, 0)
    33. return;
    34. }
    35. //已经下载了的 先计算 下载的大小,然后继续下载
    36. tmpSize = FileTool.fileSize(self.downLoadingPath!)
    37. self.downLoadWithURL(url as URL, tmpSize)
    38. }
    39. // MARK:- 开始请求资源
    40. func downLoadWithURL(_ url : URL, _ offset : CLongLong) {
    41. var request = NSURLRequest(url: url, cachePolicy: NSURLRequest.CachePolicy.reloadIgnoringCacheData, timeoutInterval: 0) as URLRequest
    42. request.setValue("bytes=%lld-", forHTTPHeaderField: "Range")
    43. let dataTask = self.session.dataTask(with: request)
    44. dataTask.resume()
    45. }
    46. }
    47. extension DownLoader : URLSessionDataDelegate {
    48. func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Swift.Void){
    49. print(response)
    50. let resp = response as! HTTPURLResponse
    51. // self.totalSize = resp.allHeaderFields["Content-Length"] as! CLongLong?
    52. // self.totalSize = String(resp.allHeaderFields["Content-Length"]).components(separatedBy: "/").last).CLongLong
    53. let string = resp.allHeaderFields["Content-Length"] as! String
    54. let stri : String = string.components(separatedBy: "/").last!
    55. self.totalSize = CLongLong(stri)!
    56. // 比对本地大小, 和 总大小
    57. if (self.tmpSize == self.totalSize) {
    58. // 1. 移动到下载完成文件夹
    59. print("移动文件到下载完成")
    60. FileTool.moveFile(self.downLoadingPath!, self.downLoadedPath!)
    61. // 2. 取消本次请求
    62. completionHandler(URLSession.ResponseDisposition.cancel);
    63. return;
    64. }
    65. if (self.tmpSize > self.totalSize) {
    66. // 1. 删除临时缓存
    67. print("删除临时缓存")
    68. FileTool.removeFile(self.downLoadingPath!)
    69. // 2. 从0 开始下载
    70. print("重新开始下载")
    71. self.downLoader(url: resp.url! as NSURL)
    72. // [self downLoadWithURL:response.URL offset:0];
    73. // 3. 取消请求
    74. completionHandler(URLSession.ResponseDisposition.cancel);
    75. return;
    76. }
    77. // 继续接受数据
    78. // 确定开始下载数据
    79. self.outputStream = OutputStream(toFileAtPath: self.downLoadingPath!, append: true)
    80. self.outputStream?.open()
    81. completionHandler(URLSession.ResponseDisposition.allow);
    82. }
    83. func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data){
    84. var buffer = [UInt8](repeating: 0, count: data.count)
    85. data.copyBytes(to: &buffer, count: data.count)
    86. self.outputStream?.write(buffer, maxLength: data.count)
    87. // let uint8Ptr = UnsafeMutablePointer<UInt8>.allocate(capacity: data.count)
    88. // uint8Ptr.initialize(from: data)
    89. // let rawPtr = UnsafeRawPointer(uint8Ptr)
    90. // self.outputStream?.write(rawPtr, maxLength: da.length)
    91. }
    92. func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?){
    93. print("请求完成")
    94. if (error == nil) {
    95. // 不一定是成功
    96. // 数据是肯定可以请求完毕
    97. // 判断, 本地缓存 == 文件总大小 {filename: filesize: md5:xxx}
    98. // 如果等于 => 验证, 是否文件完整(file md5 )
    99. }else {
    100. print("有问题")
    101. }
    102. self.outputStream?.close()
    103. }
    104. }

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

    1. import UIKit
    2. class FileTool: NSObject {
    3. // MARK:- 判断文件目录是否存在
    4. class func fileExists(filePath : String) -> Bool {
    5. if (filePath.characters.count == 0) {
    6. return false
    7. }
    8. return FileManager.default.fileExists(atPath: filePath)
    9. }
    10. // MARK:- 获取文件的大小
    11. class func fileSize(_ filePath : String) ->CLongLong{
    12. if !self.fileExists(filePath: filePath) {
    13. return 0
    14. }
    15. let fileInfo = try! FileManager.default.attributesOfItem(atPath: filePath)
    16. return fileInfo[FileAttributeKey.size] as! CLongLong
    17. }
    18. // MARK:- 移动文件
    19. class func moveFile(_ fromPath : String , _ toPath : String){
    20. if self.fileSize(fromPath) == 0 {
    21. return
    22. }
    23. try! FileManager.default.moveItem(atPath: fromPath, toPath: toPath)
    24. }
    25. class func removeFile(_ filePath : String){
    26. try! FileManager.default.removeItem(atPath: filePath)
    27. }
    28. }

    使用

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