Swift 如何查看某个文件夹是否是使用NSURL的另一个文件夹的子文件夹?

Swift 如何查看某个文件夹是否是使用NSURL的另一个文件夹的子文件夹?,swift,cocoa,nsurl,Swift,Cocoa,Nsurl,我有一个[URL],它表示一组特殊的父目录。我得到了另一个[URL],它表示分散在系统中的文件。我想知道这些文件是否在我的任何特殊目录或其子目录中是否有一种简单/预期的方法可以做到这一点,而无需手动解析/遍历绝对URL的路径?在NSURL中没有任何方法可以让您查看另一个NSURL是否代表另一个的根路径 一种可能的解决方案是使用path属性将两个URL转换为路径字符串。然后查看一个字符串是否是另一个字符串的前缀。但在获取URL路径之前,请同时使用urlbystandardingPath和URLBy

我有一个
[URL]
,它表示一组特殊的父目录。我得到了另一个
[URL]
,它表示分散在系统中的文件。我想知道这些文件是否在我的任何特殊目录或其子目录中是否有一种简单/预期的方法可以做到这一点,而无需手动解析/遍历绝对URL的路径?

NSURL
中没有任何方法可以让您查看另一个
NSURL
是否代表另一个的根路径

一种可能的解决方案是使用
path
属性将两个URL转换为路径字符串。然后查看一个字符串是否是另一个字符串的前缀。但在获取URL路径之前,请同时使用
urlbystandardingPath
URLByResolvingSymlinksInPath
以确保结果一致

例如:

NSURL *specialURL = ... // a URL for one of the special parent directories
NSURL *fileURL = ... // a URL for one of the files to check
NSString *specialPath = [specialURL.URLByStandardizingPath.URLByResolvingSymlinksInPath.path stringByAppendingString:@"/"];
NSString *filePath = fileURL.URLByStandardizingPath.URLByResolvingSymlinksInPath.path
if ([filePath hasPrefix:specialPath]) {
    // This file is in this special directory
}

前缀解决方案的问题是,它在以下情况下会失败:例如

PathA: /Documents/untitled folder (1)/SomeFolder/Xyz/Waterfall.mp3
PathB: /Documents/untitled folder
前缀解决方案将告诉您PathA是PathB的子级,尽管事实并非如此

手动遍历解决方案:

斯威夫特:
扩展字符串{
func isChildPath(路径:String的)->Bool{
self.count
目标C:
@接口NSString(添加)
-(BOOL)isChildOfPath:(NSString*)路径;
@结束
@实现NSString(添加)
-(BOOL)isChildOfPath:(NSString*)路径{
NSString*child=self;
NSString*父项=路径;
NSArray*childPathComponents=child.pathComponents;
NSArray*parentPathComponents=parent.pathComponents;
if(parentPathComponents.count>=childPathComponents.count){
返回否;
}
对于(NSInteger i=0;i
稍有改进的Swift 5版本,结合了Umair和rmaddy现有优秀答案的优秀功能

与Umair的回答一样,这正确地处理了路径中的文件夹部分匹配的情况(也就是说,它不会说
/foo/bar baz/bang
/foo/bar/
作为祖先)

它还执行规范化(标准化路径以消除
./
,以及解析符号链接),如rmaddy的答案

func pathHasAncestor(maybeChild: URL, maybeAncestor: URL) -> Bool {
    let ancestorComponents: [String] = canonicalize(maybeAncestor).pathComponents
    let childComponents: [String] = canonicalize(maybeChild).pathComponents

    return ancestorComponents.count < childComponents.count
        && !zip(ancestorComponents, childComponents).contains(where: !=)
}

func canonicalize(_ url: URL) -> URL {
    url.standardizedFileURL.resolvingSymlinksInPath()
}

在前缀测试之前,您需要在
specialPath
中添加一个尾随斜杠,否则类似
/super
的内容将被视为
/supermarket/qfc
的父项。(
NSURL
s
path
property将删除任何尾部
/
)@CRD很好,谢谢。更新。奇怪的是,当您打印表示文件夹的文件路径的
NSURL
时,会显示尾部的斜杠。但是
path
的结果不包括斜杠。但是我没有更好的解决方案。谢谢你的回答!它指出了一个非常重要的问题!如果可以的话,我查看了您的Swift代码,它与此单行版本相同:
self.count
-如果我用它更新您的答案,您是否可以?另外,用它们创建一个新的URL(使用
URL(fileURLWithPath:)
)而不是将它们连接到NSString,其成本是O(1),但可以在Ubuntu上使用。确定。你可以编辑和添加这个更简单的版本,这是非常棒的。这是非常好的!它采用了背后的理念,使其更加可靠!我想我会在
URL
func pathHasAncestor(maybeChild: URL, maybeAncestor: URL) -> Bool {
    let ancestorComponents: [String] = canonicalize(maybeAncestor).pathComponents
    let childComponents: [String] = canonicalize(maybeChild).pathComponents

    return ancestorComponents.count < childComponents.count
        && !zip(ancestorComponents, childComponents).contains(where: !=)
}

func canonicalize(_ url: URL) -> URL {
    url.standardizedFileURL.resolvingSymlinksInPath()
}
import XCTest

class FileUtilsTests: XCTestCase {
    func testPathHasAncestor() throws {
        let leaf = URL(fileURLWithPath: "/foo/bar/baz")
        let parent = leaf.deletingLastPathComponent()
        XCTAssertTrue(pathHasAncestor(maybeChild: leaf, maybeAncestor: parent))
        XCTAssertFalse(pathHasAncestor(maybeChild: URL(fileURLWithPath: "/foo/bar 1/baz"), maybeAncestor: parent))
        XCTAssertFalse(pathHasAncestor(maybeChild: leaf, maybeAncestor: leaf))
    }
}