为什么NSURL的NSURLDocumentIdentifierKey(几乎)总是为零?



OSX Yosemite在NSURL上引入了一个非常方便的属性:NSURLDocumentIdentifierKey

引用文件:

NSURLDocumentIdentifierKey

以NSNumber(只读)形式返回的文档标识符。文档标识符是由内核分配给文件或目录的值。该值用于标识文档,无论文档在卷上移动到何处。标识符会在系统重新启动时持续存在。复制文件时不会传输它,但它在"安全保存"操作中仍然有效。例如,即使在调用replaceItemAtURL:withItemAtURL:backupItemName:options:resultingItemURL:error:方法后,它仍保留在分配给它的路径上。文档标识符仅在单个卷内唯一。并非所有卷都支持此属性。

可在OS X v10.10和iOS 8.0中使用。

不幸的是,该值似乎大多为零(除了极少数看起来彼此完全断开连接的示例)。

特别是,此代码将在最后一行抛出异常(在Yosemite 10.10.3上测试):

NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *attributesFlags = @[NSURLNameKey, mNSURLDocumentIdentifierKey];
NSDirectoryEnumerator *en = [fileManager enumeratorAtURL:[NSURL URLWithString:NSHomeDirectory()]
includingPropertiesForKeys:attributesFlags
options:NSDirectoryEnumerationSkipsHiddenFiles
errorHandler:^BOOL(NSURL *url, NSError *error) {
NSAssert(NO, @"An error has occured");
return YES;
}];
for(NSURL *URL in en) {
NSNumber *documentID = nil;
NSError *error = nil;
BOOL result = [URL getResourceValue:&documentID forKey:NSURLDocumentIdentifierKey error:&error]; 
NSAssert(result == YES && error==nil, @"Unable to read property. Error: %@", error); 
NSLog(@"Processing file: %@", URL);

// This will break most of the times
NSAssert(documentID != nil, @"Document ID should not be nil!!");
}

也许我误解了文档,但在我看来,磁盘上的每个文件都应该有NSURLDocumentIdentifierKey

我就这个问题向苹果公司提交了一个错误,并得到了对我的报告的反馈。截至今天,关于跟踪DocumentIdentifier的信息还没有包含在文档中,但票证仍然开放。

缺少的信息是,文件系统默认情况下不跟踪DocumentIdentifier。您必须通过在要使用chflagsUF_TRACKED标志跟踪的每个文件上设置一个标志来启用跟踪。

以下脚本将打印文件的DocumentIdentifier

https://gist.github.com/cmittendorf/fac92272a941a9cc64d5

此脚本将启用对DocumentIdentifier:的跟踪

https://gist.github.com/cmittendorf/b680d1a03aefa08583d7

显然,Yosemite只有在知道有东西试图跟踪其身份(如版本或iCloud)时,才会为文件分配DocumentIdentifier

我看不出有任何方法可以与内核对话,并告诉它开始跟踪你感兴趣的文件。我希望这在未来的版本中会有所改变,因为API已经在OS X 10.10上公开,目前它基本上是无用的。

此问题在macOS 10.14中仍然存在。它可能不会改变。

解决方法是从NSFileManager中获取索引节点,如下所示:

NSFileManager *fmgr = [NSFileManager defaultManager];
NSDictionary *attributes = [fmgr attributesOfItemAtPath:url.path error:nil;
if (attributes != nil) {
NSNumber *inode = [attributes objectForKey:NSFileSystemFileNumber];
...
}

相关内容

最新更新