这是在Mac上:
如果我有两个文件名/ foo / foo和/ foo / FOO,它们可能引用相同的文件,或者可能是不同的文件,具体取决于文件系统。我怎么弄清楚它们是否都指向同一个文件?如果是,我如何得到正确的文件名表示?
我的问题是由链接引起的。链接可能指向/ foo / FOO,但实际目录名为/ foo / foo。
是否有任何功能会跟随链接并给我链接文件的完整路径? [NSFileManager pathContentOfSymbolicLinkAtPath]给出了可能出现错误情况的相对路径。
最终,我尝试做的是缓存文件的信息。但是如果我有两个不同的路径用于同一个文件,我的缓存可能会失去同步。
由于
答案 0 :(得分:15)
你的问题确实有几个不同的部分。通过我的阅读,你想要:
1 一种判断两个不同路径是否相同的磁盘文件的方法
2 磁盘上文件的规范名称,带有正确的大小
还有第三个问题与Display Names有关,因为在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;
//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];
}
最后,我们可以添加一些驱动程序代码并将它们整合到一个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.
答案 1 :(得分:6)
在两个路径上使用FSPathMakeRef()
,然后使用FSCompareFSRefs()
查看它们是否是同一个文件/文件夹。然后,您可以使用FSRefMakePath()
来获取规范表示,但如果您向用户显示文件名,则应使用NSFileManager's
- displayNameAtPath:
方法,因为它处理本地化和显示/正确隐藏扩展名。
答案 2 :(得分:2)
如果os x是unix派生词,你有权访问inode#?
答案 3 :(得分:0)
如果有人试图在iOS上执行此操作,则FSRef不可用。我能弄清楚如何获得具有正确大小写的“实际”文件名的唯一方法是列出父目录的内容,然后匹配。
iOS是区分大小写的文件系统,而OS X(和模拟器)则不是。我编写了这段代码来检测给定路径何时存在,但在sim中有错误的情况。
如果有人有更好的方法来做到这一点(除了这个丑陋的循环)我都是耳朵。
void checkForCapsIssues(NSString* compiledPath)
{
NSArray* validFilePaths = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[[compiledPath stringByDeletingLastPathComponent] stringByResolvingSymlinksInPath] error:nil];
NSString* lastPathComponent = [compiledPath lastPathComponent];
for (NSString* fileName in validFilePaths) {
if([fileName isEqualToString:lastPathComponent])
{
return;
}
if([[fileName lowercaseString] isEqualToString:[lastPathComponent lowercaseString]])
{
NSLog(@"Warning! Caps Problem Found! %@", compiledPath);
return;
}
}
}
答案 4 :(得分:-2)
AFAIK,默认情况下Mac OS X中的文件系统是Case Insensitive,因此链接或文件名的大小写无关紧要。