【问题标题】:Does the isDirectory parameter to +[NSURL fileURLWithPath:isDirectory:] need to be correct?+[NSURL fileURLWithPath:isDirectory:] 的 isDirectory 参数是否需要正确?
【发布时间】:2013-09-11 00:03:15
【问题描述】:

我一直在使用+[NSURL fileURLWithPath:],因为它很方便,但在分析中我发现这是瓶颈的根源,因为它在调用+[NSURL fileURLWithPath:isDirectory:](或Core Foundation 等效项)之前会查询文件系统:

此方法假定path 是一个以斜杠结尾的目录。 如果path 不以斜线结尾,则该方法检查文件系统 确定path 是文件还是目录。如果path 存在于 文件系统并且是一个目录,该方法附加一个斜杠。 如果文件系统中不存在path,则该方法假定它 代表一个文件,不附加斜杠。

如果可能,我想避免这种开销。但我并不总是提前知道我正在构建的 URL 是否是一个目录。例如,可能只给我一个路径,或者给我一个目录和其中的项目(未知类型)的名称。我的问题是,是否可以始终将 NO 传递给 isDirectory,即使结果可能不准确?

特别是,我想确保这不会搞砸 -[NSURL getResourceValue:forKey:error:]NSFileManager

一些基本测试并未发现此优化有任何不良后果,但这并不意味着没有任何不良后果。我不太清楚为什么NSURL 首先关心isDirectory。查看CFURLsource,代码似乎试图确保目录路径始终以斜杠结尾。但是,除了显示目的之外,我不清楚为什么这对文件系统路径很重要。 (在使用 NSString 表示路径时,这从来都不是问题。)+[NSURL fileURLWithPath:isDirectory:] 的文档说 isDir 是:

一个布尔值,指定是否将path 视为目录 解析相对路径组件时的路径。传递YES 如果 path 表示目录,NO 否则。

确实,如果我使用-[NSURL initWithString:relativeToURL:],则新 URL 不包含baseURL 的最后一个组件,除非它是使用YESisDirectory 创建的。但是,我认为我从未调用过此方法,而且系统似乎不需要代表我这样做(对于上述用例)。我注意到-[NSURL URLByAppendingPathComponent:] 会在必要时插入一个斜杠,而不是假设IS_DIRECTORY 标志是正确的。那么,除了创建相对 URL 之外,这个标志是否重要?即使我愿意,在一般情况下似乎也不可能总是传递正确的值。文件系统总是可以从我下面改变。如果我使用+[NSURL fileURLWithPath:],系统也无法始终确定它,因为文件系统中可能尚不存在该路径。

【问题讨论】:

    标签: macos cocoa filepath nsfilemanager nsurl


    【解决方案1】:

    如果您传入 NO 并始终创建非目录 URL,那么对于使用 URL 访问文件系统的任何例程(例如 -getResourceValue:forKey:error:NSFileManager)来说,这绝对没问题。

    对于file URL,只有当您想要解析 URL 的路径时,尾部斜杠才真正变得重要。即这个sn-p:

    NSURL *baseURL = [NSURL fileURLWithPath:path isDirectory:YES];
    NSURL *result = [NSURL URLWithString:@"relative/path" relativeToURL:baseURL];
    

    将产生与此不同的结果:

    NSURL *baseURL = [NSURL fileURLWithPath:path isDirectory:NO];
    NSURL *result = [NSURL URLWithString:@"relative/path" relativeToURL:baseURL];
    

    实际上,处理file URL 的相对字符串/路径并不常见。远程 URL 更需要它(当然取决于您的应用程序做什么!)

    【讨论】:

    • 谢谢。听起来你同意我的假设。但是,当您要求操作系统执行文件系统操作时,它是否真的记录(承诺)了操作系统不会创建相对 URL 的任何地方?
    【解决方案2】:

    这里是an example 重要的地方。

    【讨论】:

      【解决方案3】:

      不,根据我的经验,isDirectory: 参数不需要正确。相反,将 isDirectory: 参数设置为 YES,并不能保证 url.path 将以文件夹斜杠结尾。

      我对此进行了一些测试,并了解到这完全取决于 fileURLWithPath: 是否可以在文件系统中验证,并且在沙盒应用程序中可能并不总是可行。

      这就解释了为什么沙盒应用程序中的这个测试有一个完美的分数,尽管这几乎不是人们希望的行为:

      - (void)testFileURLWithPathIsDirectory
      {
          NSString *path = NSHomeDirectory();
          XCTAssertTrue([path isEqualToString:@"/Users/myUser"], @"%@", path);
          
          NSURL *pathURL = [NSURL fileURLWithPath:NSHomeDirectory() isDirectory:YES];
          XCTAssertTrue([pathURL.path isEqualToString:@"/Users/myUser"], @"%@", pathURL.path);
          
          XCTAssertFalse([pathURL.path isEqualToString:@"file:///Users/myUser/"], @"%@", pathURL.path);
      }
      

      显然,isDirectory 应该被视为一个提示,开发人员应该记住,fileURLWithPath: 和 fileURLWithPath:isDirectory: 将根据 URL 的沙盒状态生成不同的路径。

      最后一个问题:指向包的 URL 的路径永远不会有尾部斜杠,但如果 URL 指向包中的文件,则该路径将表明包只是一个目录。

      【讨论】:

        猜你喜欢
        • 2012-03-07
        • 2015-02-11
        • 2012-10-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-08-18
        • 1970-01-01
        相关资源
        最近更新 更多