你的问题实际上有几个不同的部分。根据我的理解,您希望:
1 一种方法来判断两个不同路径是否为相同的磁盘文件
2 确定磁盘上文件的规范名称,并使用正确的大小写
还有一个涉及到
显示名称的第三个问题,因为在OS X中,文件可以本地化其名称,并对不同的语言环境显示不同的名称。所以我们再加上:
3 获取显示名称的方法,因为我们可能想要根据用户看到文件系统的方式缓存某些内容,而不是终端中文件系统的显示方式。
我们可以通过@boaz-stuller提出的FSRef技巧来解决
1。或者这里有一些使用更高级别的Cocoa调用的代码,这样我们就可以节省一些内存操作(因为我们可以让
NSAutoreleasePool
代劳):
long getInode(NSString* path) {
NSFileManager* fm = [NSFileManager defaultManager];
NSError* error;
NSDictionary* info = [fm attributesOfItemAtPath:path error:&error];
NSNumber* inode = [info objectForKey:NSFileSystemFileNumber];
return [inode longValue];
}
但要解决2,我们必须使用FSRefs来找到文件的规范大小写:
NSString* getActualPath(NSString* path) {
FSRef ref;
OSStatus sts;
UInt8* actualPath;
sts = FSPathMakeRef((const UInt8 *)[path UTF8String], &ref, NULL);
if (sts) return [NSString stringWithFormat:@"Error #%d making ref.", sts];
actualPath = malloc(sizeof(UInt8)*MAX_PATH_LENGTH);
sts = FSRefMakePath(&ref, actualPath, MAX_PATH_LENGTH);
if (sts) return [NSString stringWithFormat:@"Error #%d making path.", sts];
return [NSString stringWithUTF8String:(const char*)actualPath];
}
这并不错,但是当我们能够使用Cocoa方法解决3时,我们会更加高兴:
NSString* getDisplayPath(NSString* path) {
NSFileManager* fm = [NSFileManager defaultManager];
NSString* mine = [fm displayNameAtPath:path];
NSString* parentPath = [path stringByDeletingLastPathComponent];
NSString* parents = [@"/" isEqualToString:parentPath]
? @""
: getDisplayPath(parentPath);
return [NSString stringWithFormat:@"%@/%@", parents, mine];
}
最后,我们可以添加一些驱动程序代码,并将其全部绑定到CoreFoundation命令行工具中(我不得不添加AppKit框架才能使其编译)。
NSString* fileInfoString(NSString* path) {
long inode = getInode(path);
return [NSString stringWithFormat:
@"\t%@ [inode #%d]\n\t\tis actually %@\n\t\tand displays as %@",
path,
inode,
getActualPath(path),
getDisplayPath(path)];
}
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
if (argc < 2) {
NSLog(@"Usage: %s <path1> [<path2>]", argv[0]);
return -1;
}
NSString* path1 = [NSString stringWithCString:argv[1]];
NSString* path2 = argc > 2
? [NSString stringWithCString:argv[1]]
: [path1 uppercaseString];
long inode1 = getInode(path1);
long inode2 = getInode(path2);
NSString* prefix = [NSString stringWithFormat:
@"Comparing Files:\n%@\n%@",
fileInfoString(path1),
fileInfoString(path2)];
int retval = 0;
if (inode1 == inode2) {
NSLog(@"%@\nSame file.", prefix);
} else {
NSLog(@"%@\nDifferent files.", prefix);
retval = 1;
}
[pool drain];
return retval;
}
现在,我们可以把所有内容都放在一起并运行它:
$ checkpath /users/tal
2008-12-15 23:59:10.605 checkpath[22375:10b] 比较文件:
/users/tal [inode #1061692]
实际路径为 /Users/tal
显示路径为 /Users/tal
/USERS/TAL [inode #1061692]
实际路径为 /Users/tal
显示路径为 /Users/tal
同一个文件。