mralexhay
mralexhay

Reputation: 1304

Get the names of files in an iCloud Drive folder that haven't been downloaded yet

I’m trying to get the names of all files and folders in an iCloud Drive directory:

import Foundation

let fileManager = FileManager.default
let directoryURL = URL(string: "folderPathHere")!

do {
    let directoryContents = try fileManager.contentsOfDirectory(at: directoryURL, includingPropertiesForKeys: nil, options: [.skipsSubdirectoryDescendants, .skipsHiddenFiles])
    for url in directoryContents {
        let fileName = fileManager.displayName(atPath: url.absoluteString)
        print(fileName)
    }
} catch let error {
    let directoryName = fileManager.displayName(atPath: directoryURL.absoluteString)
    print("Couldnt get contents of \(directoryName): \(error.localizedDescription)")
}

It appears that any iCloud files that haven’t been downloaded to the device don’t return URLs.

I know I can check if a path contains a ubiquitous item when I already know the path with the code below (even if it isn’t downloaded):

fileManager.isUbiquitousItem(at: writePath)

Is there a way to get the URLs & names of those iCloud files without downloading them first?

The directory URL is a security-scoped URL constructed from bookmark data in case that makes any difference (omitted that code here for clarity).

Thanks

Upvotes: 6

Views: 1392

Answers (3)

Patrick Beard
Patrick Beard

Reputation: 622

The better way to remove the "." and ".icloud" elements from file names in iCloud drive is to use FileManager.displayName(atPath:). It also presents the names of other application containers using the name of the application, instead of the more generic "Documents".

Upvotes: 0

Agost Biro
Agost Biro

Reputation: 2839

You need to use a NSFileCoordinator to access the directory in iCloud Storage, and then normalize placeholder file names for items that haven't been downloaded yet:

let iCloudDirectoryURL = URL(...)

let fileCoordinator = NSFileCoordinator(filePresenter: nil)
fileCoordinator.coordinate(
    readingItemAt: iCloudDirectoryURL,
    options: NSFileCoordinator.ReadingOptions(),
    error: nil
) { readingURL in
    do {
        let contents = try FileManager.default.contentsOfDirectory(
            at: readingURL, includingPropertiesForKeys: nil
        )
        for url in contents {
            print("\(canonicalURL(url))")
        }
    } catch {
        print("Error listing iCloud directory: '\(error)'")
    }
}

func canonicalURL(_ url: URL) -> URL {
    let prefix = "."
    let suffix = ".icloud"
    var fileName = url.lastPathComponent
    if fileName.hasPrefix(prefix), fileName.hasSuffix(suffix) {
        fileName.removeFirst(prefix.count)
        fileName.removeLast(suffix.count)
        var result = url.deletingLastPathComponent()
        result.append(path: fileName)
        return result
    } else {
        return url
    }
}

Upvotes: 0

mralexhay
mralexhay

Reputation: 1304

Found the answer. I was skipping hidden files with ".skipsHiddenFiles", but the non-downloaded files are actually hidden files, named: ".fileName.ext.iCloud".

Remove the skips hidden files option now works as expected.

Upvotes: 2

Related Questions