问题
I have an original file, /path/to/foo.txt
, and a symbolic link to it, /other/path/to/foo.txt
. I delete /path/to/foo.txt
, but leave the symbolic link in-place. How can I tell that the symbolic link still exists using Cocoa APIs?
I found this by using the standard/recommended FileManager.fileExists(atPath:). The problem here, for anyone unfamiliar with that API, is that it traverses symlinks. So, when I do this:
FileManager.default.fileExists(atPath: "/other/path/to/foo.txt")
it returns false
, because it saw that I gave it a symlink and resolved it, and then saw that there is no file at the resolved path.
As the documentation says:
If the file at
path
is inaccessible to your app, perhaps because one or more parent directories are inaccessible, this method returnsfalse
. If the final element inpath
specifies a symbolic link, this method traverses the link and returnstrue
orfalse
based on the existence of the file at the link destination.
There doesn't seem to be an alternative in FileManager
. So, I'm wondering if I can call a Cocoa API to tell if a symlink exists there, or if I'll have to resort to C or Bash APIs.
回答1:
Here's a simpler way: 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:
You don't need/use FileManager for this. And you should not be using string file paths for anything any more.
Start with a file URL — the URL version of your "/other/path/to/foo.txt"
. Now read the file's .isSymbolicLink
resource key and see whether it's a symbolic link. If it is, but if the file pointed to doesn't exist, you know your link has gone bad.
I wrote a little test in a playground:
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)
}
}
回答3:
A solution to replace fileExists(atPath:) is to use attributesOfItem(atPath:) that returns the type of node (FileAttributeKey.type) and throws and error Code=260 if file/node doesn't exist.
So here my "interpretation" with that:
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
}
}
}
Way to dig the error code <<< Thanks to Ben Leggiero for the trick :-)
来源:https://stackoverflow.com/questions/51901378/how-can-i-tell-if-a-symbolic-link-exists-at-a-certain-path