快速获取文件的别名路径
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