【问题标题】:Download in documents directory or move file async - iOS在文档目录中下载或异步移动文件 - iOS
【发布时间】:2017-02-13 16:33:26
【问题描述】:

我正在构建一个 iOS 应用程序,用户可以在其中下载不同的文件。
我正在使用URLSessionDownloadTaskURLSession 异步下载文件。
下载完成后,目标文件夹默认为tmp/ 目录。
因此,当下载结束时,我需要将临时文件移动到另一个目录。
对于图片或歌曲,这只需 1 秒甚至更短。
但是当文件是视频时,例如,最多可能需要 15 秒。

问题

为了让用户仍能与应用进行交互,我想将此移动设为异步。
每次我尝试这样做时,文件管理器都会引发异常。

“CFNetworkDownload_xxxxxx.tmp”无法移动到“下载”,因为前者不存在,或者包含后者的文件夹不存在。

我尝试了什么

我试图将文件管理器的调用放在后台线程中,它抛出了。

我尝试在调用 move 方法之前删除目标文件,以确保该文件不存在。

在从tmp/ 目录中删除文件之前,我尝试调用copy 函数。

我的代码

对文件管理器的调用看起来像这样。

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

问题

如何在不影响 UI 的情况下移动一个非常大的文件?

将文件直接下载到永久目录中将是一个更好的解决方案。我该怎么做?

当我同步调用我的simpleMove(from:to:) 时,它运行良好。
那么,为什么错误说目标目录不存在? (或类似的东西,我不确定那个错误的含义)

谢谢。

注意

上面的代码是用 Swift 3 编写的,但如果您有 Objective-C 或 Swift 2 的答案,
也欢迎分享!

【问题讨论】:

  • 你找出原因了吗?我太坚持这个了。

标签: ios asynchronous download nsurlsession nsfilemanager


【解决方案1】:

有趣的是,对此的correct answer 被发布在另一个问题中,它不是正确的答案。

Apple's Documentation 中介绍了解决方案,他们在其中声明:

位置

临时文件的文件 URL。由于该文件是临时文件,因此在从此委托方法返回之前,您必须打开文件进行读取或将其移动到应用沙箱容器目录中的永久位置。

如果您选择打开文件进行读取,您应该在另一个线程中进行实际读取以避免阻塞委托队列。

您可能从 DownloadTask 的成功处理程序调用 simpleMove。当您在后台线程上调用 simpleMove 时,成功处理程序会返回并且您的临时文件会在 simpleMove 被调用之前被清理。

解决办法是按照苹果的说法,打开文件进行阅读:

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

【讨论】:

    【解决方案2】:

    我遇到了同样的问题,但我解决了。

    首先检查该文件是否存在于该路径中,因为路径扩展名与位置 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
         }
     }
    

    希望对你有帮助

    【讨论】:

    • 您的回答一般适用于错误消息“CFNetworkDownload_xxxxxx.tmp” couldn’t be moved to “Downloads” because either the former doesn't exist, or the folder containing the latter doesn't exist.,但不适用于所讨论的实际情况。
    猜你喜欢
    • 2015-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-25
    • 1970-01-01
    • 2015-01-07
    • 2015-08-08
    • 1970-01-01
    相关资源
    最近更新 更多