Search code examples
iosswiftnsfilemanager

Copying remote file to temporary ios File gives error: File Exists


I am downloading an Excel file from a URL and trying to copy the excel file into a local temporary file. The temporary file path is unique every time because temporary directory gives a unique UUID string based path.

For example, on the first time the path is:

file:///private/var/mobile/Containers/Data/Application/FCA022DB-3B65-499E-9F91-190E307285B0/tmp/WindData.csv

The second time the path is different:

/private/var/mobile/Containers/Data/Application/6CB02402-837D-4952-8C56-58572705B0AD/tmp/WindData.csv

But I get the error "File exists" the second time even though path is unique. So check if the file exists by FileManager.default.fileExists and if found true then I delete the filepath. This check returns a false as if the file does not exist, but in the the very next line When I try to copy the destination file to target Url (because it does not exist from previous line), it gives error:

"Error: Error Domain=NSCocoaErrorDomain Code=516 "“CFNetworkDownload_oHoanb.tmp” couldn’t be copied to “tmp” because an item with the same name already exists." UserInfo={NSSourceFilePathErrorKey=/private/var/mobile/Containers/Data/Application/DB863D34-3F66-45C8-B129-76DB6FC61D0E/tmp/CFNetworkDownload_oHoanb.tmp, NSUserStringVariant=( Copy ), NSDestinationFilePath=/private/var/mobile/Containers/Data/Application/DB863D34-3F66-45C8-B129-76DB6FC61D0E/tmp/WindData.csv, NSFilePath=/private/var/mobile/Containers/Data/Application/DB863D34-3F66-45C8-B129-76DB6FC61D0E/tmp/CFNetworkDownload_oHoanb.tmp, NSUnderlyingError=0x2801e93b0 {Error Domain=NSPOSIXErrorDomain Code=17 "File exists"}}"

How to fix this?

 let datadownloadTask = URLSession.shared.downloadTask(with: vendorURL!, completionHandler: { (responseUrl, response, error) in
        do {
            if let tempUrl = responseUrl {
                if let statusCode = (response as? HTTPURLResponse)?.statusCode {
                    print("Successfully downloaded. Status code: \(statusCode)")
                }

                do {
                    let targetUrl = self.copyResourcetoTempFile(sourceUrl: tempUrl, resourceName: "WindData", fileExtension: "csv")
                    if let destUrl = targetUrl {
                        let data = try String(contentsOfFile: destUrl.absoluteString!, encoding: .utf8)
                        let avg = self.parseCsv(data: data)
                        self.avg = avg
                    }

                } catch (let writeError) {
                    print("Error creating a file \(tempUrl) : \(writeError)")
                }

                completion(self.avg)
            }
        } catch {
            print("error: \(error.localizedDescription)")
        }
    })
    datadownloadTask.resume()
}

public func copyResourcetoTempFile(sourceUrl: URL, resourceName: String, fileExtension: String) -> NSURL?
{
    let tempDirectoryURL = NSURL.fileURL(withPath: NSTemporaryDirectory(), isDirectory: true)
    let targetUrl = tempDirectoryURL.appendingPathComponent(resourceName).appendingPathExtension(fileExtension)
    do {
        if FileManager.default.fileExists(atPath: targetUrl.absoluteString) {
           try FileManager.default.removeItem(at: targetUrl)
        }
        try FileManager.default.copyItem(at: sourceUrl, to: targetUrl)
        return targetUrl as NSURL
    } catch let error {
        NSLog("Error: \(error)")
    }
    return nil
}

Solution

  • You are making a very common mistake:

    The path of a file system URL is path, not absoluteString, the latter represents the whole URL including the scheme.

    if FileManager.default.fileExists(atPath: targetUrl.path) {
    

    And there is no reason to use NSURL in Swift

    let tempDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
    

    or meanwhile still more convenient

    let tempDirectoryURL = URL.temporaryDirectory