如何确定某个路径上是否存在符号链接?

时间:2018-08-17 18:55:49

标签: swift cocoa symlink nsfilemanager symlink-traversal

我有一个原始文件/path/to/foo.txt,并有一个指向该文件的符号链接/other/path/to/foo.txt。我删除了/path/to/foo.txt,但将符号链接保留在原处。 如何使用Cocoa API判断符号链接是否仍然存在?


我通过使用标准/推荐的FileManager.fileExists(atPath:)找到了这一点。对于不熟悉该API的任何人来说,这里的问题是它遍历符号链接。所以,当我这样做时:

FileManager.default.fileExists(atPath: "/other/path/to/foo.txt")

它返回false,因为它看到我给了它一个符号链接并对其进行了解析,然后看到在解析的路径中没有文件。

如文档所述:

  

如果您的应用无法访问path中的文件,可能是因为无法访问一个或多个父目录,则此方法返回false。如果path中的最后一个元素指定了符号链接,则此方法将遍历该链接并根据文件在链接目的地的存在情况返回truefalse

FileManager中似乎没有其他选择。因此,我想知道是否可以调用Cocoa API来告知其中是否存在符号链接,还是必须使用C或Bash API。

3 个答案:

答案 0 :(得分:3)

您不需要/使用FileManager。而且,您不应再将字符串文件路径用于任何

以文件URL开头-"/other/path/to/foo.txt"的URL版本。现在,读取文件的.isSymbolicLink资源密钥,看看它是否是符号链接。如果是,但是如果指向的文件不存在,则说明您的链接已损坏。

我在操场上做了一个小测试:

let url = URL(fileURLWithPath: "/Users/mattneubelcap/Desktop/test.txt")
if let ok = try? url.checkResourceIsReachable(), ok {
    let vals = url.resourceValues(forKeys: [.isSymbolicLinkKey])
    if let islink = vals.isSymbolicLink, islink {
        print("it's a symbolic link")
        let dest = url.resolvingSymlinksInPath()
        let report = dest != url ? "It exists" : "It doesn't exist"
        print(report)
    }
}

答案 1 :(得分:2)

这是一种更简单的方法:Fondation / FileManger / FileWrapper

let node = try FileWrapper(url: URL(fileURLWithPath: "/PATH/file.link"), options: .immediate)

node.isDirectory      >> false
node.isRegularFile    >> false
node.isSymbolicLink   >> true

答案 2 :(得分:1)

替换fileExists(atPath :)的解决方案是使用attributesOfItem(atPath :) 返回节点的类型(FileAttributeKey.type),如果文件/节点不存在,则抛出错误Code = 260。

这就是我的“解释”:

func nodeExists(atPath path: String) -> FileType? {
do {
    let attribs = try fm.attributesOfItem(atPath: path)
    if let type = attribs[FileAttributeKey.type] {
        switch (type as! FileAttributeType) {
            case FileAttributeType.typeDirectory: return .directory
            case FileAttributeType.typeRegular: return .file
            case FileAttributeType.typeSymbolicLink: return .symlink
            default:
                return nil
            }
        }
    } catch {
        if (error as NSError).code == 260 {
            return false
        } else {
            return nil
        }
    }
}

如何提取错误代码<<<感谢Ben Leggiero的技巧:-)