【问题标题】:How to find the location of file under a directory tree?如何在目录树下找到文件的位置?
【发布时间】:2018-09-19 18:19:47
【问题描述】:

给定一个文件名,比如 foo.txt 和一个基本目录 URL,比如 ~/bar/directory 找到第一次出现的子目录的最佳方法是什么文件?

  • Foundation 或 AppKit 中是否存在现有 API?
  • 例如,通过子树进行广度优先搜索是否可行?看起来怎么样?
  • 另一种方式?

【问题讨论】:

    标签: macos appkit foundation


    【解决方案1】:

    一种选择是手动枚举目录:

    func manualSearchFile(withName name: String, in path: String) {
    
        func search(url: URL) {
            do {
                let contents = try FileManager.default.contentsOfDirectory(at: url, includingPropertiesForKeys: [.nameKey, .pathKey, .isDirectoryKey], options: [])
                try contents.forEach {
                    let metadata = try $0.resourceValues(forKeys: [.nameKey, .pathKey, .isDirectoryKey])
                    if metadata.name == name {
                        print("Manual Found: \(metadata.path ?? "unknown path")")
                    }
                    if metadata.isDirectory == true {
                        search(url: $0)
                    }
                }
            } catch {
                print(error)
            }
        }
    
        search(url: URL(fileURLWithPath: path))
    }
    manualSearchFile(withName: "foo.txt", in: "/bar/directory")
    

    另一种选择是使用 Spotlight,它速度更快,但仅适用于已编入索引的路径。许多系统目录被排除在外,用户可以在“系统偏好设置”>“聚焦”>“隐私”中排除更多。

    var metadataQuery: NSMetadataQuery?
    func spotlightSearchFile(withName name: String, in path: String) {
    
        NotificationCenter.default.addObserver(forName: .NSMetadataQueryDidFinishGathering, object: nil, queue: nil) {
    
            guard let query = $0.object as? NSMetadataQuery else { return }
            query.enumerateResults { (result, index, cancel) in
    
                let item = result as? NSMetadataItem
                let path = item?.value(forAttribute: NSMetadataItemPathKey) as? String
                print("Spotlight Found: \(path ?? "unknown path")")
            }
        }
    
        metadataQuery = NSMetadataQuery()
        metadataQuery?.searchScopes = [path]
        metadataQuery?.predicate = NSPredicate(format: "%K like[cd] %@", NSMetadataItemDisplayNameKey, name)
        metadataQuery?.start()
    }
    spotlightSearchFile(withName: "foo.txt", in: "/bar/directory")
    

    有关查询语法的更多信息,请参阅Comparison of NSPredicate and Spotlight Query Strings

    在过去,我们使用FSCatalogSearchFSGetCatalogInfoBulk 有更多选择。但是这些不再可用,AFAIK。

    【讨论】:

    • 那是一个 DFS 解决方案,对吧?即,将首先遍历目录直到它们的叶子,而不是在继续子目录之前搜索目录的所有内容。 NSFileManager.enumerate 函数不也提供什么吗?我对偏好匹配文件而不是目录的 BFS 更感兴趣。
    • 我不确定,但是 - 已经看到它运行了数百次 - linux ‘find’ 看起来 BFS
    猜你喜欢
    • 2023-03-16
    • 2019-06-01
    • 2021-03-17
    • 2014-09-08
    • 2014-08-30
    • 2018-04-01
    • 1970-01-01
    • 2018-05-21
    • 2014-04-29
    相关资源
    最近更新 更多