我正在构建一个iOS应用程序,用户可以在其中下载不同的文件
我正在使用URLSessionDownloadTask
和URLSession
异步下载文件。
下载完成后,目标文件夹默认为tmp/
目录。
因此,当下载结束时,我需要将临时文件移动到另一个目录。
对于图片或歌曲,这只需要1秒甚至更短。
但是当文件是一个视频时例如,最多可能需要15秒。
为了让用户仍然可以与应用程序进行交互,我想将此移动异步。
每次尝试这样做时,文件管理器都会抛出异常。
“CFNetworkDownload_xxxxxx.tmp”无法移至“下载”,因为前者不存在,或者包含后者的文件夹不存在。
我试图在后台线程中调用文件管理器,它会抛出。
我尝试在调用move方法之前删除目标文件,以确保该文件不存在。
在从copy
目录中删除文件之前,我尝试调用tmp/
函数。
对文件管理器的调用看起来就是这样。
func simpleMove(from location: URL, to dest: URL) -> Bool {
let fileManager = FileManager.default
do {
try fileManager.moveItem(at: location, to: dest)
return true
} catch {
print("\(error.localizedDescription)")
return false
}
}
当我把它放在后台线程中时,我会这样做。
DispatchQueue.global().async {
if !simpleMove(from: location, to: dest) {
//Failure
}
}
如何在不影响用户界面的情况下移动真正大的文件?
直接在永久目录中下载文件将是更好的解决方案。我怎么能这样做?
当我同步拨打simpleMove(from:to:)
时,它可以正常工作。
那么,为什么错误表明目标目录不存在? (或类似的东西,我不确定该错误的含义)
感谢。
上面的代码是用Swift 3编写的,但是如果你有Objective-C或Swift 2的答案,也可以随意分享!
答案 0 :(得分:2)
有趣的是,对此的correct answer被发布在另一个问题中,它不是正确的答案。
解决方案在Apple's Documentation中进行了说明,其中指出:
位置
临时文件的文件URL。由于该文件是临时文件,因此您必须先打开文件以进行读取,或者将其移至应用的沙箱容器目录中的永久位置,然后再从此委托方法返回。
如果选择打开文件进行读取,则应在另一个线程中进行实际读取,以避免阻塞委托队列。
您可能正在从DownloadTask的成功处理程序中调用simpleMove
。当您在后台线程上调用simpleMove
时,成功处理程序将返回,并且临时文件将在simpleMove
被调用之前被清除。
解决方案是按照Apple所说的做,然后打开文件进行读取:
public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
do {
let file: FileHandle = try FileHandle(forReadingFrom: location)
DispatchQueue.global().async {
let data = file.readDataToEndOfFile()
FileManager().createFile(atPath: destination, contents: data, attributes: nil)
}
} catch {
// Handle error
}
}
答案 1 :(得分:0)
我遇到了同样的问题,但我解决了这个问题。
首先检查文件是否存在于该路径中,因为我遇到了问题,因为路径扩展名与位置URL不同。我试图重命名音频,但路径扩展不同(例如,mp3到m4a)
此外,如果目标路径上已存在任何其他文件 这个问题出现了。
首先尝试使用
检查存在于您所在位置的文件 let fileManager = FileManager.default
if fileManager.fileExists(atPath: location.path) {
do {
try fileManager.moveItem(at: location, to: dest)
return true
} catch {
print("\(error.localizedDescription)")
return false
}
}
希望这会对你有所帮助