在文档目录中下载或移动文件异步 - iOS

时间:2016-10-05 09:37:04

标签: ios asynchronous download nsurlsession nsfilemanager

我正在构建一个iOS应用程序,用户可以在其中下载不同的文件 我正在使用URLSessionDownloadTaskURLSession异步下载文件。
下载完成后,目标文件夹默认为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的答案,也可以随意分享!

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
     }
 }

希望这会对你有所帮助