Получение псевдонима пути к файлу в swift
У меня проблемы с разрешением ссылки на псевдоним на Mac. Я проверяю, является ли файл псевдонимом, и затем я хотел бы получить исходный путь. Вместо этого я получаю только File-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, что делает его более гибким
4 ответа
Ответ vadian отлично работает на 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, в отличие от решения vadian. Если кто-то может пролить свет на это, пожалуйста, помогите.
- Однако любое из этих решений выполняется в сценарии оболочки со строкой shebang.
#!/usr/bin/env swift
,
- Однако любое из этих решений выполняется в сценарии оболочки со строкой shebang.
Если вы хотите явно проверить, является ли данный путь псевдонимом Finder, посмотрите этот ответ, который получен из vadian, но из-за его более узкого фокуса также работает на 10.9.
Это решение с использованием 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
}
Будьте внимательны, чтобы предоставить соответствующие права, если функция вызывается в изолированной среде.
Вот реализация 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
}
}
Вариант 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
}