我如何解决Objective-C中的相对路径?

时间:2013-06-30 22:52:07

标签: objective-c nsurl nsfilemanager

我正在尝试下面的代码,看看我是否可以扩展这些位置的绝对路径,以便我可以将它们用于NSFileManager的操作,当我使用波浪号和相对路径时它会失败。

我正在使用Objective-C中的Xcode中的命令行应用程序。我可以从命令行运行该程序,它为我扩展了路径,但是从Xcode中的目标我使用$ PROJECT_DIR和$ HOME传递命令行参数的值,以便让我在那里的一部分。问题是我需要到$ PROJECT_DIR / ..这不能解决NSFilemanager。

看起来URLByResolvingSymlinksInPath或URLByStandardizingPath没有像我期望的那样工作。还有其他我应该做的事吗?

BOOL isDir = TRUE;
for (NSString *path in @[@"~/", @".", @".."]) {
    NSURL *url = [[[NSURL URLWithString:path] URLByResolvingSymlinksInPath] URLByStandardizingPath];
    DebugLog(@"path: %@", url.absoluteString);
    DebugLog(@"Exists: %@", [[NSFileManager defaultManager] fileExistsAtPath:url.path isDirectory:&isDir] ? @"YES" : @"NO");
}

更新:我使用stdlib的realpath解析路径并创建了以下方法虽然我不理解这个C函数。具体来说,我不知道解决的价值是什么,或者我将如何使用它。我确实看到了预期的回报值。

- (NSString *)resolvePath:(NSString *)path {
    NSString *expandedPath = [[path stringByExpandingTildeInPath] stringByStandardizingPath];
    const char *cpath = [expandedPath cStringUsingEncoding:NSUTF8StringEncoding];
    char *resolved = NULL;
    char *returnValue = realpath(cpath, resolved);

//    DebugLog(@"resolved: %s", resolved);
//    DebugLog(@"returnValue: %s", returnValue);

    return [NSString stringWithCString:returnValue encoding:NSUTF8StringEncoding];
}

3 个答案:

答案 0 :(得分:9)

在您的示例中的路径中,只有~/是绝对路径,因此只有~/可能会转换为绝对路径。

但是唉,NSURL根本没有解决波浪号(~)。您必须使用-[NSString stringByStandardizingPath]-[NSString stringByExpandingTildeInPath]来扩展代字号。

如果不指定相对于哪个网址,则无法将.转换为绝对网址。 NSURL不会假设您想要使用进程的当前目录。你必须明确。

出于同样的原因,无法解决..

您没有在问题中提及此问题,但在somename/..中,无法解析..,因为somename可能最终成为符号链接,{{1跟随符号链接后,您可能会转到与包含..的目录不同的目录。

不幸的是,somename文档没有提到这些限制。 NSString documentation确实如此。

您可以使用NSURL获取当前目录,将其传递给-[NSFileManager currentDirectoryPath],并将结果(当前目录的绝对+[NSURL fileURLWithPath:] URL)传递给file解析+[NSURL URLWithString:relativeToURL:].和符号链接。

答案 1 :(得分:2)

您的示例路径分为两组:波浪路径和“点”路径。

对于波形路径,您必须在代码中展开它们,文本系统无法识别波浪号,但这是命令行解释器(也称为“shell”,CLI)引入的简写。要进行扩展,您可以使用stringByExpandingTildeInPath

等方法

“点”路径不同,“。”和“..”目录条目作为文件系统的一部分存在,包含它们的路径可以工作。

然而,路径以“。”开头。或“..”被视为相对于当前工作目录(CWD)。虽然CWD对于CLI来说是显而易见的,但是对于GUI应用程序来说它可能设置得不那么明显 - 这意味着虽然这些路径可行,但它们可能不会引用您在启动GUI应用程序后所期望的操作。但是,您可以设置CWD,请参阅changeCurrentDirectoryPath:,在以“。”开头的路径之后。或“......”应该引用你的期望。

答案 2 :(得分:2)

以下是我的解决方案,它运行良好,使用较低级别的C函数,我试图避免。它符合我的目的。使用的完整项目可以在GitHub上使用我为下面的Objective-C创建的方法。

https://github.com/brennanMKE/Xcode4CodeSnippets/tree/master/SnippetImporter

- (NSString *)resolvePath:(NSString *)path {
    NSString *expandedPath = [[path stringByExpandingTildeInPath] stringByStandardizingPath];
    const char *cpath = [expandedPath cStringUsingEncoding:NSUTF8StringEncoding];
    char *resolved = NULL;
    char *returnValue = realpath(cpath, resolved);

    if (returnValue == NULL && resolved != NULL) {
        printf("Error with path: %s\n", resolved);
        // if there is an error then resolved is set with the path which caused the issue
        // returning nil will prevent further action on this path
        return nil;
    }

    return [NSString stringWithCString:returnValue encoding:NSUTF8StringEncoding];
}