在文档目录中下载或异步移动文件-iOS [英] Download in documents directory or move file async - iOS

查看:263
本文介绍了在文档目录中下载或异步移动文件-iOS的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am building an iOS app in which the user can download different files.
I am using an URLSessionDownloadTask and an URLSession to download a file asynchronously.
When the download is finished, the destination folder is by default, the tmp/ directory.
So, when the download ends, I need to move the temporary file to another directory.
For a picture or a song, this takes only 1 second maybe even less.
But when the file is a video for example, it can take up to 15 seconds.

为了允许用户仍然与应用程序交互,我想使此动作异步.
每次尝试这样做时,文件管理器都会引发异常.

To allow the user to still interact with the app, I would like to make this move asynchronous.
Each time I try to do that, the file manager throws an exception.

"CFNetworkDownload_xxxxxx.tmp"无法移至下载",因为前者不存在或包含后者的文件夹不存在.

"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.

我尝试了什么

我试图将对文件管理器的调用放在一个后台线程中,它会抛出.

What have I tried

I tried to put the call to the file manager in a background thread, it throws.

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

I tried to remove the destination file before calling the move method, to make sure that the file doesn't already exists.

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

I tried to make a call to the copy function, before removing the file from the tmp/ directory.

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

The call to the file manager looks like that.

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

当我将其放在后台线程中时,我会那样做.

When I put that in a background thread, I do it like that.

DispatchQueue.global().async {
    if !simpleMove(from: location, to: dest) {
        //Failure
    }
}

问题

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

Questions

How can I possibly move a really large file without affecting the UI?

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

It would be an even better solution to download the file directly in a permanent directory. How can I do that?

当我同步调用simpleMove(from:to:)时,它可以正常工作.
那么,为什么错误提示目标目录不存在? (或类似的东西,我不确定该错误的含义)

When I make the call to my simpleMove(from:to:) synchronously, it works perfectly.
So, why the error says that the destination directory doesn't exists? (or something like that, I'm not sure of the meaning of that error)

谢谢.

上面的代码是用Swift 3编写的,但是如果您有Objective-C或Swift 2的答案,那么也可以随意共享它!

The code above is written in Swift 3, but if you have an Objective-C or a Swift 2 answer,
feel free to share it as well!

推荐答案

有趣的是,发布了正确答案在另一个问题中,这不是正确的答案.

Amusingly, the correct answer to this was posted in another question, where it was not the correct answer.

Apple的文档中说明了该解决方案,其中指出:

The solution is covered in Apple's Documentation where they state:

位置

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

A file URL for the temporary file. Because the file is temporary, you must either open the file for reading or move it to a permanent location in your app’s sandbox container directory before returning from this delegate method.

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

If you choose to open the file for reading, you should do the actual reading in another thread to avoid blocking the delegate queue.

您可能正在从DownloadTask的成功处理程序中调用simpleMove.当您在后台线程上调用simpleMove时,成功处理程序将返回,并且甚至在调用simpleMove之前都会清理您的临时文件.

You are probably calling simpleMove from the success handler for the DownloadTask. When you call simpleMove on a background thread, the success handler returns and your temp file is cleaned up before simpleMove is even called.

解决方案是按照Apple所说的做,然后打开文件进行读取:

The solution is to do as Apple says and open the file for reading:

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

这篇关于在文档目录中下载或异步移动文件-iOS的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆