这是在 Mac 上:
如果我有两个文件名/foo/foo 和/foo/FOO,它们可能指的是同一个文件,也可能是不同的文件,具体取决于文件系统。我如何确定它们是否都指向同一个文件?如果是,我如何获得文件名的正确表示?
我的问题是由链接引起的。链接可能指向/foo/FOO,但实际目录名为/foo/foo。
是否有任何函数可以跟随链接并为我提供链接文件的完整路径? [NSFileManager pathContentOfSymbolicLinkAtPath] 给出可能大小写不正确的相对路径。
最终我要做的是缓存文件信息。但是,如果同一个文件有两个不同的路径,我的缓存可能会不同步。
谢谢
最佳答案
您的问题确实有几个不同的部分。根据我的阅读,你想要:
1 a way to tell if two different paths are the same on-disk file
2 a canonical name for the file on disk, with the proper casing
还有第三个问题也与Display Names有关。 ,因为在 OS X 中,文件可以本地化其名称并针对不同的语言环境显示不同的内容。所以让我们添加
3 a way to get the display name, because we might want to cache things depending on how the user sees the file system, not how the file system appears in the terminal.
我们可以使用 @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;
//first get an FSRef for the path
sts = FSPathMakeRef((const UInt8 *)[path UTF8String], &ref, NULL);
if (sts) return [NSString stringWithFormat:@"Error #%d making ref.", sts];
//then get a path from the FSRef
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];
}
最后,我们可以添加一些驱动程序代码并将它们全部绑定(bind)到一个 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] Comparing Files: /users/tal [inode #1061692] is actually /Users/tal and displays as /Users/tal /USERS/TAL [inode #1061692] is actually /Users/tal and displays as /Users/tal Same file.
关于objective-c - 如何找到文件名的正确大小写?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/370186/