Cocoa(Swift):如何修改文件下载目标路径至下载文件夹?
修改Swift Cocoa应用的文件下载路径至系统下载文件夹
你说得没错,问题确实出在路径获取的部分!在Cocoa应用的沙盒环境中,.documentDirectory指向的是应用私有库目录下的Documents文件夹(也就是~/Library/Containers/[你的应用Bundle ID]/Data/Documents),这就是为什么你觉得文件存在Library里的原因。
要将文件保存到系统默认的下载文件夹,你需要做两个关键修改:
1. 使用正确的文件夹类型和域
替换原来的.documentDirectory为.downloadsDirectory,并且确保使用.userDomainMask(指定当前用户的域,而不是.allDomainsMask,后者可能返回不符合预期的系统级路径)。
另外,不要用强制解包!,改用guard安全获取路径,避免找不到下载文件夹时崩溃。
2. 添加沙盒访问权限
在沙盒环境下,Cocoa应用访问用户的下载文件夹需要申请权限。你需要在Info.plist中添加NSDownloadsFolderUsageDescription键,填写一段说明文字(比如"需要访问下载文件夹以保存您下载的文件"),否则应用会被拒绝访问该目录。
修改后的完整代码
下面是更新后的FileDownloader类,我已经替换了路径获取逻辑,并完善了错误处理:
import Foundation class FileDownloader { static func loadFileSync(url: URL, completion: @escaping (String?, Error?) -> Void) { // 获取用户的下载文件夹路径 guard let downloadsUrl = FileManager.default.urls(for: .downloadsDirectory, in: .userDomainMask).first else { let error = NSError(domain:"FileDownloadError", code:1003, userInfo:[NSLocalizedDescriptionKey: "无法找到系统下载文件夹"]) completion(nil, error) return } let destinationUrl = downloadsUrl.appendingPathComponent(url.lastPathComponent) if FileManager().fileExists(atPath: destinationUrl.path) { print("文件已存在 [\(destinationUrl.path)]") completion(destinationUrl.path, nil) } else if let dataFromURL = NSData(contentsOf: url) { if dataFromURL.write(to: destinationUrl, atomically: true) { print("文件已保存 [\(destinationUrl.path)]") completion(destinationUrl.path, nil) } else { print("保存文件失败") let error = NSError(domain:"FileDownloadError", code:1001, userInfo:[NSLocalizedDescriptionKey: "保存文件失败"]) completion(destinationUrl.path, error) } } else { let error = NSError(domain:"FileDownloadError", code:1002, userInfo:[NSLocalizedDescriptionKey: "下载文件失败"]) completion(destinationUrl.path, error) } } static func loadFileAsync(url: URL, completion: @escaping (String?, Error?) -> Void) { // 获取用户的下载文件夹路径 guard let downloadsUrl = FileManager.default.urls(for: .downloadsDirectory, in: .userDomainMask).first else { let error = NSError(domain:"FileDownloadError", code:1003, userInfo:[NSLocalizedDescriptionKey: "无法找到系统下载文件夹"]) completion(nil, error) return } let destinationUrl = downloadsUrl.appendingPathComponent(url.lastPathComponent) if FileManager().fileExists(atPath: destinationUrl.path) { print("文件已存在 [\(destinationUrl.path)]") completion(destinationUrl.path, nil) } else { let session = URLSession(configuration: URLSessionConfiguration.default, delegate: nil, delegateQueue: nil) var request = URLRequest(url: url) request.httpMethod = "GET" let task = session.dataTask(with: request, completionHandler: { data, response, error in if let error = error { completion(destinationUrl.path, error) return } guard let response = response as? HTTPURLResponse, response.statusCode == 200 else { let statusError = NSError(domain:"FileDownloadError", code:1004, userInfo:[NSLocalizedDescriptionKey: "服务器响应错误"]) completion(destinationUrl.path, statusError) return } guard let data = data else { let dataError = NSError(domain:"FileDownloadError", code:1005, userInfo:[NSLocalizedDescriptionKey: "未获取到下载数据"]) completion(destinationUrl.path, dataError) return } do { try data.write(to: destinationUrl, options: .atomic) completion(destinationUrl.path, nil) } catch { completion(destinationUrl.path, error) } }) task.resume() } } }
补充说明
你之前尝试修改为.desktopDirectory没生效,大概率也是因为权限问题——访问桌面文件夹同样需要在Info.plist中添加NSDesktopFolderUsageDescription权限说明,不过既然你的需求是下载文件夹,用上面的方案就可以了。
内容的提问来源于stack exchange,提问作者user13647535




