Getting file path alias in swift

I'm having trouble resolving the alias link on mac. I check if the file is an alias, and then I want to get the source path. Instead, I only get File-Id. Obsessions?

func isFinderAlias(path:String) -> Bool? { var isAlias:Bool? = false // Initialize result var. // Create a CFURL instance for the given filesystem path. // This should never fail, because the existence isn't verified at this point. // Note: No need to call CFRelease(fUrl) later, because Swift auto-memory-manages CoreFoundation objects. print("path before \(path)"); let fUrl = CFURLCreateWithFileSystemPath(nil, path, CFURLPathStyle.CFURLPOSIXPathStyle, false) print("path furl \(fUrl)"); // Allocate void pointer - no need for initialization, // it will be assigned to by CFURLCopyResourcePropertyForKey() below. let ptrPropVal = UnsafeMutablePointer<Void>.alloc(1) // Call the CoreFoundation function that copies the desired information as // a CFBoolean to newly allocated memory that prt will point to on return. if CFURLCopyResourcePropertyForKey(fUrl, kCFURLIsAliasFileKey, ptrPropVal, nil) { // Extract the Bool value from the memory allocated. isAlias = UnsafePointer<CFBoolean>(ptrPropVal).memory as Bool // it will be assigned to by CFURLCopyResourcePropertyForKey() below. let ptrDarwin = UnsafeMutablePointer<DarwinBoolean>.alloc(1) if ((isAlias) == true){ if let bookmark = CFURLCreateBookmarkDataFromFile(kCFAllocatorDefault, fUrl, nil){ let url = CFURLCreateByResolvingBookmarkData(kCFAllocatorDefault, bookmark.takeRetainedValue(), CFURLBookmarkResolutionOptions.CFBookmarkResolutionWithoutMountingMask, nil, nil, ptrDarwin, nil) print("getting the path \(url)") } } // Since the CF*() call contains the word "Copy", WE are responsible // for destroying (freeing) the memory. ptrDarwin.destroy() ptrDarwin.dealloc(1) ptrPropVal.destroy() } // Deallocate the pointer ptrPropVal.dealloc(1) return isAlias } 

EDIT: Both Answers are correct! I would choose the answer mklement0 because of the originally unclaimed requirement that the code work on 10.9, which makes it more flexible.

+5
source share
4 answers

vadian answer works great on OS X 10.10+ .

Here's an implementation that also works on OS X 10.9 :

 // OSX 10.9+ // Resolves a Finder alias to its full target path. // If the given path is not a Finder alias, its *own* full path is returned. // If the input path doesn't exist or any other error occurs, nil is returned. func resolveFinderAlias(path: String) -> String? { let fUrl = NSURL(fileURLWithPath: path) var targetPath:String? = nil if (fUrl.fileReferenceURL() != nil) { // item exists do { // Get information about the file alias. // If the file is not an alias files, an exception is thrown // and execution continues in the catch clause. let data = try NSURL.bookmarkDataWithContentsOfURL(fUrl) // NSURLPathKey contains the target path. let rv = NSURL.resourceValuesForKeys([ NSURLPathKey ], fromBookmarkData: data) targetPath = rv![NSURLPathKey] as! String? } catch { // We know that the input path exists, but treating it as an alias // file failed, so we assume it not an alias file and return its // *own* full path. targetPath = fUrl.path } } return targetPath } 

Note:

  • Unlike the vadian solution, this will return the value even for files with an alias, namely for this file, the full full path and the path NSURL will be used instead of entering an NSURL instance.

  • The vadian solution requires the appropriate rights to use the function in the isolated application / environment. It seems that this, at least, does not need it to the same extent as in the Xcode Playground, unlike the vadian solution. If anyone can shed light on this, please help.

    • Any solution, however, is executed in a shell script with the shebang line #!/usr/bin/env swift .
  • If you want to explicitly check if a given path is an alias of Finder, see this answer , which is obtained from Wadans, but due to its narrower focus, also works on 10.9.

+2
source

This is a solution using NSURL .

It expects an NSURL object as a parameter and returns the original path if url is an alias or nil .

 func resolveFinderAlias(url:NSURL) -> String? { var isAlias : AnyObject? do { try url.getResourceValue(&isAlias, forKey: NSURLIsAliasFileKey) if isAlias as! Bool { do { let original = try NSURL(byResolvingAliasFileAtURL: url, options: NSURLBookmarkResolutionOptions()) return original.path! } catch let error as NSError { print(error) } } } catch _ {} return nil } 

Swift 3:

 func resolveFinderAlias(at url: URL) -> String? { do { let resourceValues = try url.resourceValues(forKeys: [.isAliasFileKey]) if resourceValues.isAliasFile! { let original = try URL(resolvingAliasFileAt: url) return original.path } } catch { print(error) } return nil } 

Be aware to grant appropriate rights if the function is called in an isolated environment.

+5
source

It implements the Swift 3 implementation, based mainly on the Vanadium approach. My idea is to return the file url, so I effectively combine it with fileURLWithPath . This is an extension of the NSURL class because I need to be able to call it from existing Objective-C code:

 extension NSURL { class func fileURL(path:String, resolveAlias yn:Bool) -> URL { let url = URL(fileURLWithPath: path) if !yn { return url } do { let vals = try url.resourceValues(forKeys: [.isAliasFileKey]) if let isAlias = vals.isAliasFile { if isAlias { let original = try URL(resolvingAliasFileAt: url) return original } } } catch { return url // give up } return url // really give up } } 
+1
source

URL option I need to return nil (and not an alias or error), otherwise the original is Swift4

 func resolvedFinderAlias() -> URL? { if (self.fileReferenceURL() != nil) { // item exists do { // Get information about the file alias. // If the file is not an alias files, an exception is thrown // and execution continues in the catch clause. let data = try NSURL.bookmarkData(withContentsOf: self as URL) // NSURLPathKey contains the target path. let rv = NSURL.resourceValues(forKeys: [ URLResourceKey.pathKey ], fromBookmarkData: data) var urlString = rv![URLResourceKey.pathKey] as! String if !urlString.hasPrefix("file://") { urlString = "file://" + urlString } return URL.init(string: urlString) } catch { // We know that the input path exists, but treating it as an alias // file failed, so we assume it not an alias file so return nil. return nil } } return nil } 
0
source

Source: https://habr.com/ru/post/1234533/


All Articles