objective-c - 如何找到文件名的正确大小写?

标签 objective-c cocoa macos

这是在 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/

相关文章:

xcode - Cocos2d-x OS X 应用程序菜单

python - 不从终端运行应用程序时, "print"到哪里?

ios - iOS 应用程序能否在 Xcode 模拟器中运行以访问 Mac 硬盘驱动器位置(在沙箱之外)

java - MacOS Catalina(v 10.15.3) : Error: “chromedriver” cannot be opened because the developer cannot be verified. 无法启动 Chrome 浏览器

objective-c - 从 TableView 初始化的 JTRevealSidebar

cocoa - NSArrayController 的绑定(bind)在哪里声明的?

ios - 在 iOS 中是否可以通过 WhatsApp 将文本发送到特定的联系号码?

macos - 如何编译 .nib 文件

iphone - iPhone-如何测试每个内存调用返回的分配对象?

ios - UICollectionView 在按钮按下时无意滚动