我无法在Swift中使用文件引用URL。首先,Swift的URL
类型甚至没有定义将文件路径URL转换为文件引用URL的方法。 NSURL
有这样一种方法:fileReferenceURL() -> URL?
,但我无法弄清楚如何让它发挥作用。
我尝试了什么:
let myURL = URL(string: "file:///Users/Me/Desktop/CoolFolder")!
let refURL = (myURL as NSURL).fileReferenceURL()!
NSLog("\(myURL)") // file:///Users/Me/Desktop/CoolFolder (ok)
NSLog("\(refURL)") // file:///Users/Me/Desktop/CoolFolder (wha?!?)
logFolderContents() // Logs contents of folder pointed to by refURL
// ...
// Rename CoolFolder -> UncoolFolder in Finder.
// ...
logFolderContents() // Fails!
// ...
// Rename UncoolFolder -> CoolFolder.
// ...
logFolderContents() // Successfully logs contents again.
基本上,refURL
继续指向原始文件路径。对fileReferenceURL()
的调用似乎什么也没做。
如何在Swift中获取文件引用URL?
更新 用户@Sam在评论中指出这似乎是一个Swift 3回归错误,如下所示:https://bugs.swift.org/browse/SR-2728。请访问该链接并对此错误进行投票。该线程还包含一个解决方法。
答案 0 :(得分:1)
遗憾的是,截至 2021 年 4 月,该错误仍未修复。这使得比较文件 URL 的相等性变得非常困难。
使用 ObjC 效果很好:
NSString *p1 = @"/etc/hosts";
NSString *p2 = @"/private/etc/hosts";
NSURL *url1 = [NSURL fileURLWithPath:p1];
NSURL *url2 = [NSURL fileURLWithPath:p2];
NSURL *ref1 = url1.fileReferenceURL;
NSURL *ref2 = url2.fileReferenceURL;
BOOL equal = [ref1 isEqual:ref2];
在 Swift 中,我得到了几乎相同的结果(即包含卷 ID 和文件 ID 的 64 位):
let p1 = "/etc/hosts"
let p2 = "/private/etc/hosts"
let url1 = URL(fileURLWithPath: p1)
let url2 = URL(fileURLWithPath: p2)
// This does not work because the refs do not use fileIDs as they should
// See https://bugs.swift.org/browse/SR-2728
let ref1bad = (url1 as NSURL).fileReferenceURL()!
let ref2bad = (url2 as NSURL).fileReferenceURL()!
let equalBad = ref1bad == ref2bad
print("\(ref1bad) = \(ref2bad): \(equalBad)")
// This works:
var ref1: NSObject?
var ref2: NSObject?
if let resourceValues = try? url1.resourceValues(forKeys: [.fileResourceIdentifierKey]) {
ref1 = resourceValues.fileResourceIdentifier as? NSObject
}
if let resourceValues = try? url2.resourceValues(forKeys: [.fileResourceIdentifierKey]) {
ref2 = resourceValues.fileResourceIdentifier as? NSObject
}
let equal = ref1!.isEqual(ref2) // the use of "!" is probably not good here
print("\(String(describing: ref1)) = \(String(describing: ref2)): \(equal)")
如果你想要一个真正的文件引用 URL,你必须从对象中的两个 32 位值(它似乎是 NSData
类型)重建 URL,并使用第一个作为文件 ID 和第二个作为volumeID。不过,为此编写代码超出了我目前相当微薄的 Swift 技能。