Search code examples
iosswiftswift2nsurlnsfilemanager

Get Document Directory Inbox file and move


I have an incoming PDF attachment coming into my app. It's coming in as NSURL assigned in the AppDelegate:

func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool {

The file prints to the print log as:

Incoming File: file:///private/var/mobile/Containers/Data/Application/65E4F19F-98DD-4A4E-8A49-E1C564D135D8/Documents/Inbox/Burrito.pdf

How can I get the file out of the DocumentDirectory Inbox folder where it is put by default for an incoming file? I tried to create a new folder called "Recipes" and then move it to this folder, but it won't I get the error:

Unable to create directory Error Domain=NSCocoaErrorDomain Code=516 "“Burrito-2.pdf” couldn’t be moved to “Documents” because an item with the same name already exists." UserInfo={NSSourceFilePathErrorKey=/private/var/mobile/Containers/Data/Application/D5C9B472-B880-4D68-BA0D-31BA545E2150/Documents/Inbox/Burrito.pdf, NSUserStringVariant=( Move ), NSDestinationFilePath=/var/mobile/Containers/Data/Application/D5C9B472-B880-4D68-BA0D-31BA545E2150/Documents/Recipes, NSFilePath=/private/var/mobile/Containers/Data/Application/D5C9B472-B880-4D68-BA0D-31BA545E2150/Documents/Inbox/Burrito.pdf, NSUnderlyingError=0x13912e0e0 {Error Domain=NSPOSIXErrorDomain Code=17 "File exists"}}

My code to move the file is:

    // Incoming file
    print("Incoming File: \(incomingFileTransfer)")

    // File Manager
    let filemgr = NSFileManager.defaultManager()

    // Document Directory
    var dirPaths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)

    // Documents Location
    let docsDir = dirPaths[0] //as! String
    print("Documents Folder: \(docsDir)")

    print("------------------------")

    // Create a new folder in the directory named "Recipes"
    print("Creating new folder...")
    let documentsPath = NSURL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0])
    let newPath = documentsPath.URLByAppendingPathComponent("Recipes")
    do {
        try NSFileManager.defaultManager().createDirectoryAtPath(newPath.path!, withIntermediateDirectories: true, attributes: nil)
    } catch let error as NSError {
        NSLog("Unable to create directory \(error.debugDescription)")
    }
    print("New Path: \(newPath)")
    print("------------------------")


    // Moving item in folder
    print("Moving PDf file to new folder...")

    let startingPath = incomingFileTransfer
    let endingPath = newPath

    do {
       try filemgr.moveItemAtURL(startingPath, toURL: endingPath)
    } catch let error as NSError {
        NSLog("Unable to create directory \(error.debugDescription)")
    }

I'm new to Swift and have been research online and documentation on file management, but can't figure this out. I looked here but it is different and also in Objective-C; converting to Swift is hard for me. I'm using Xcode7 and Swift2, Thank you.


Solution

  • You get the errors when you run the application the second time and the directory is already created and the file has already been moved.

    Apple highly recommends to use the URL related API of NSFileManager

    First get the documents directory

    // File Manager
    let filemgr = NSFileManager.defaultManager()
    
    // Document Directory
    let docsDirURL = try! filemgr.URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: true)
    

    The try! statement is safe because the documents directory always exists.

    Then check if the Recipes directory exists. If not, create it

    let recipesURL = docsDirURL.URLByAppendingPathComponent("Recipes")
    if !filemgr.fileExistsAtPath(recipesURL.path!) {
      do {
        try filemgr.createDirectoryAtURL(recipesURL, withIntermediateDirectories: false, attributes: nil)
        print("Directory created at: \(recipesURL)")
      } catch let error as NSError {
        NSLog("Unable to create directory \(error.debugDescription)")
        return
      }
    }
    

    You can also check if the destination file exists

    let incomingFileName = incomingFileTransfer.lastPathComponent!
    
    let startingURL = incomingFileTransfer
    let endingURL = recipesURL.URLByAppendingPathComponent(incomingFileName)
    
    if !filemgr.fileExistsAtPath(endingURL.path!) {
      do {
        try filemgr.moveItemAtURL(startingURL, toURL: endingURL)
      } catch let error as NSError {
        NSLog("Unable to move file \(error.debugDescription)")
      }
    }