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

3

6

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

Cattalo answered 8/4, 2020 at 20:0 Comment(1)
Note that absoluteString it is not the same as path. You should use url.pathLorielorien
C
2

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.

Cattalo answered 9/4, 2020 at 23:28 Comment(1)
Is looking into hidden files and removing the leading dot and the ".iCloud" the way to go here? I'm trying to do exactly as you and I'm not sure if the right way to do it is using NSMetadataQuery. @Cattalo Is your solution still working fine?Kirmess
S
0

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
    }
}
Saraann answered 8/1, 2023 at 18:30 Comment(0)
M
0

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

Memphis answered 24/5 at 2:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.