快速获取文件的别名路径

Posted

技术标签:

【中文标题】快速获取文件的别名路径【英文标题】:Getting alias path of file in swift 【发布时间】:2015-10-26 14:47:19 【问题描述】:

我无法解析 mac 上的别名链接。我正在检查文件是否是别名,然后我想接收原始路径。相反,我只得到一个文件 ID。 只有想法?

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

编辑: 两个答案都是正确的! 我会选择 mklement0 的答案,因为最初没有说明要求代码在 10.9 上运行,这使得它更加灵活

【问题讨论】:

您是否有理由使用 Core Foundation 而不是 Foundation(即NSURL)? 如何使用 Foundation 检查别名? 【参考方案1】:

这是使用NSURL 的解决方案。

它需要一个 NSURL 对象作为参数,如果 url 是别名,则返回原始路径或 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

斯威夫特 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

如果在沙盒环境中调用函数,请注意提供适当的权利。

【讨论】:

有趣的解决方案。但是 NSURLBookmarkResolutionOptions 在 10.10 或新版本上不可用(收到错误消息)另外 byResolvingAliasFileAtUrl 将无法使用 10.10 之前的版本,是吗? NSURLBookmarkResolutionOptions 从 10.6 开始可用,NSURL(byResolvingAliasFileAtURL:options:) 从 10.10 开始可用 @Silve2611:也许你只是忘记了import Foundation 很好的解决方案;请注意,Xcode Playground 显然也是沙盒化的,因此您不能在那里尝试该功能,但它确实可以通过带有 shebang 行 #!/usr/bin/env swift 的脚本工作。通过[ NSURLBookmarkResolutionOptions.WithoutUI , NSURLBookmarkResolutionOptions.WithoutMounting] 而不是NSURLBookmarkResolutionOptions() 可能有意义;狡辩:由于函数返回类型String?,所以在return original.path! 中使用! 没有意义 很好的解决方案。我将其标记为正确。但是,如果有人可以为 10.9 展示如何做到这一点,那就太好了。我生病了继续努力。【参考方案2】:

vadian's answer 在 OS X 10.10+ 上运行良好。

这是一个也适用于 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's not an alias file and return its
        // *own* full path.
        targetPath = fUrl.path
    
  
  return targetPath

注意:

与 vadian 的解决方案不同,这将返回一个值,即使对于 -别名文件,即该文件的 自己的完整路径,并采用路径字符串而不是NSURL 实例作为输入。

vadian 的解决方案需要适当的权利才能在沙盒应用程序/环境中使用该功能。 似乎这个至少不需要 在相同程度上,因为它Xcode Playground,与 vadian 的解决方案不同。 如果有人能阐明这一点,请提供帮助。

然而,这两种解决方案确实shell 脚本中运行,shebang 行#!/usr/bin/env swift

如果您想明确测试给定路径是否是 Finder 别名,请参阅this answer,它源自 vadian,但由于其关注范围更窄,也适用于 10.9。

【讨论】:

感谢您的出色解决方案!你帮了我很多!不幸的是,我已经将一个答案标记为正确,因为它是一个可行的解决方案。这个解决方案更好! @Silve2611 很高兴听到这个消息;请至少 up-vote vadian 的答案,并可能在您的问题中说明您选择此答案的更新,因为最初没有说明代码也可以在 10.9 上运行。【参考方案3】:

这是一个 Swift 3 实现,主要基于 vadian 的方法。我的想法是返回一个文件 URL,所以我有效地将它与fileURLWithPath 结合起来。这是一个 NSURL 类扩展,因为我需要能够从现有的 Objective-C 代码中调用它:

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
    

【讨论】:

【参考方案4】:

我需要返回 nil(不是别名或错误)的 URL 变体,否则是原始的 - 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's not an alias file so return nil.
            return nil
        
    
    return nil

【讨论】:

以上是关于快速获取文件的别名路径的主要内容,如果未能解决你的问题,请参考以下文章

在快速选择/捕获后获取文件路径给出错误域=nscocoaerrordomain code=260

如何在 iPhone 中快速从文件路径 url 获取视频或图像?

解析 Apache VHosts 以获取域和文件夹路径列表

java项目中文件的路径

常用PowerShell命令

keystore文件