如何批量下载视频?URLSession downloadTask遇文件覆盖问题求方案
嘿,我刚好碰到过几乎一模一样的问题!你遇到的文件覆盖问题,大概率是因为所有下载任务都复用了同一个固定文件名,再加上后台下载的任务跟踪没跟上,导致新下载的文件直接覆盖了旧的。给你几个实用的解决思路和代码示例:
核心解决思路:给每个下载文件分配唯一标识
1. 生成独一无二的文件名
这是从根源上避免覆盖的关键,常见的生成方式有两种,按需选:
- 用UUID生成完全随机的唯一字符串(简单粗暴,绝对不会重复):
func generateUniqueFileName() -> String { // 记得根据你的视频格式调整后缀,比如.mp4/.mov return UUID().uuidString + ".mp4" } - 对视频原URL做哈希处理(既能保证唯一,还能和原资源关联):
func fileName(from url: URL) -> String { let urlHash = url.absoluteString.hashValue return "\(urlHash).mp4" }
2. 给每个下载任务绑定专属保存路径
创建下载任务时,把对应的唯一文件名存在任务的taskDescription里(或者维护一个字典跟踪任务和文件名的映射),这样后台回调时能准确找到目标路径:
func startBackgroundDownload(with videoURL: URL) { let uniqueFileName = generateUniqueFileName() let downloadTask = URLSession.shared.downloadTask(with: videoURL) // 把文件名存到任务描述里,方便后续回调取用 downloadTask.taskDescription = uniqueFileName downloadTask.resume() }
3. 在下载完成回调中正确处理文件移动
不要用固定路径!从任务描述里取出之前设置的唯一文件名,再移动临时文件到文档目录的对应位置:
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { // 先拿到文档目录路径 guard let documentsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { print("无法获取文档目录") return } // 从任务描述里取出预先设置的唯一文件名 guard let targetFileName = downloadTask.taskDescription else { print("无法获取当前任务的目标文件名") return } let targetURL = documentsDir.appendingPathComponent(targetFileName) // 保险起见,先检查目标路径是否存在(虽然我们用了唯一文件名,还是避免意外) if FileManager.default.fileExists(atPath: targetURL.path) { try? FileManager.default.removeItem(at: targetURL) } // 移动临时下载文件到目标路径 do { try FileManager.default.moveItem(at: location, to: targetURL) print("视频下载完成,路径:\(targetURL.path)") } catch { print("移动下载文件失败:\(error.localizedDescription)") } }
4. 后台下载的额外注意点
- 如果你的APP需要长期在后台处理下载,记得在
AppDelegate/SceneDelegate里实现handleEventsForBackgroundURLSession方法,确保后台任务完成后能正确更新状态或通知用户。 - 如果需要跟踪更多下载信息(比如视频标题、进度),可以维护一个
[URLSessionTask: DownloadInfo]的字典,DownloadInfo是自定义的模型类,比只用taskDescription更灵活。
内容的提问来源于stack exchange,提问作者iHarshad
相关产品推荐
相关产品推荐

