Проверьте, является ли NSURL каталогом

#swift #nsurl

#swift #nsurl

Вопрос:

При использовании Swift я хочу проверить, является ли NSURL местоположение каталогом. С Objective-C это не проблема и рабочая находка, но когда я конвертирую код в Swift, я сталкиваюсь с ошибкой времени выполнения.

Может быть, кто-нибудь может указать мне правильное направление?

 import Foundation

let defaultManager = NSFileManager.defaultManager()
let documentsDirectory = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0] as NSURL
let localDocumentURLs = defaultManager.contentsOfDirectoryAtURL(documentsDirectory,
includingPropertiesForKeys: nil, options: .SkipsPackageDescendants, error: nil) as NSURL[]

for url in localDocumentURLs {
    var isError: NSError? = nil
    var isDirectory: AutoreleasingUnsafePointer<AnyObject?> = nil
    var success: Bool = url.getResourceValue(isDirectory, forKey: NSURLIsDirectoryKey, error: amp;isError)
}
  

Комментарии:

1. где именно происходит ошибка во время выполнения?

Ответ №1:

В iOS 9.0 и macOS 10.11 есть свойство в NSURL / URL

Swift:

 var hasDirectoryPath: Bool { get }
  

Objective-C:

 @property(readonly) BOOL hasDirectoryPath;
  

Однако это надежно только для URL-адресов, созданных с FileManager помощью API, который гарантирует, что строковый путь словаря заканчивается косой чертой.

Для URL-адресов, созданных с использованием пользовательских литеральных строковых путей, предпочтительнее считывать значение ресурса isDirectory

Swift:

 let isDirectory = (try? url.resourceValues(forKeys: [.isDirectoryKey]))?.isDirectory ?? false
  

Objective-C:

 NSNumber *isDirectory = nil;
[url getResourceValue:amp;isDirectory forKey:NSURLIsDirectoryKey error:nil];
NSLog(@"%i", isDirectory.boolValue);
  

Комментарии:

1. действительно жаль, что этот ответ появляется только где-то посередине.

2. @ThomasKilian Вопрос был задан и на него был дан ответ в 2014 году, iOS 9 была выпущена примерно год спустя 😉

3. Что ж, сегодня это ответ. Так часто меня поражает, что правильный ответ находится где-то посередине, а не сверху.

4. Это свойство не просматривает файловую систему, чтобы выяснить, действительно ли URL-адрес указывает на каталог: URL(string: "file:///var/")!.hasDirectoryPath is true (обратите внимание на конец / ), в то время URL(string: "file:///var")!.hasDirectoryPath как is false . Проверка resourceValues — лучший подход.

5. Реальный ответ, без сомнения

Ответ №2:

Swift 3

 extension URL {
    var isDirectory: Bool {
        let values = try? resourceValues(forKeys: [.isDirectoryKey])
        return values?.isDirectory ?? false
    }
}
  

Комментарии:

1. Идеальный способ узнать наверняка!

Ответ №3:

это хорошо работает с моей стороны:

 var error: NSError?
let documentURL : NSURL = NSFileManager.defaultManager().URLForDirectory(NSSearchPathDirectory.DocumentDirectory, inDomain: NSSearchPathDomainMask.UserDomainMask, appropriateForURL: nil, create: true, error: amp;error)
var isDirectory: ObjCBool = ObjCBool(0)
if NSFileManager.defaultManager().fileExistsAtPath(documentURL.path, isDirectory: amp;isDirectory) {
    println(isDirectory)
}
  

ПРИМЕЧАНИЕ: он проверяет, является ли Documents папка папкой. конечно, вы можете заменить URL на что угодно.

Комментарии:

1. спасибо, этот подход работает — я внес некоторые небольшие изменения, потому что NSFileManager.defaultManager().fileExistsAtPath(url.path, isDirectory: amp;isDirectory) возвращает allows true в моем случае? isDirectory на самом деле содержит реальную информацию. Большое спасибо за вашу помощь.

2. да, fileExistsAtPath() возвращает, существует ли путь, isDirectory будет содержать информацию о том, является ли путь папкой или нет.

3. Человек… Я делал var isDir:ObjCBool = false вместо var isDir:ObjCBool = ObjCBool(0) этого, теперь я понимаю это false и true автоматически подключаюсь к NSNumber, а не к ObjCBool.

Ответ №4:

Вот версия swift 2.0 исходного кода poster:

         do {
            var rsrc: AnyObject?
            try element.getResourceValue(amp;rsrc, forKey: NSURLIsDirectoryKey)
            if let isDirectory = rsrc as? NSNumber {
                if isDirectory == true {
                    // ...
                }
            }
        } catch {
        }
  

Ответ №5:

Здесь много ответов… но у всех у них есть одна общая черта:
Все они используют FileManager (что и есть на самом деле NSFileManger ).

У этого подхода есть один недостаток: он FileManager не является потокобезопасным!Параллельное использование a FileManager из разных потоков обычно работает для операций без состояния, но это нигде не гарантируется (возможно, вы основываетесь на неопределенном поведении, когда полагаетесь, что это работает).

Безопасная реализация должна была бы FileManager каждый раз создавать новый экземпляр, но это было бы ужасной производительностью или использовать по одному на поток, что требует огромных затрат на управление.

Я хотел бы представить здесь гораздо лучший и гораздо более простой подход, который не требует какого-либо стороннего класса:

 extension URL {
    var isDirectory: Bool? {
        do {
            let values = try self.resourceValues(
                forKeys:Set([URLResourceKey.isDirectoryKey])
            )
            return values.isDirectory
        } catch  { return nil }
    }
}
  

Вот и все. Используя resourceValues() метод, вы также можете легко запрашивать другую интересную информацию, например, размер файла или дату последнего изменения. Это очень мощный API, который существует целую вечность и для NSURL Obj-C.

Ответ №6:

мои 2 цента… быстрый способ NSURL: (на основе ответа holex)

 var error: NSError?

// since getting it as URLForDirectory, it flags it as dir, for custom path: NSURL:fileURLWithPath:isDirectory:
let documentURL:NSURL = NSFileManager.defaultManager().URLForDirectory(NSSearchPathDirectory.DocumentDirectory, inDomain: NSSearchPathDomainMask.UserDomainMask, appropriateForURL: nil, create: true, error: amp;error)

// passes true, if it exists and validates as dir (as flagged in the NSURL object)
if (documentURL.checkResourceIsReachableAndReturnError(amp;error) {
    println(error)
}
  

Ответ №7:

… и это расширение Swift 3 на FileManager :

 extension FileManager {
    func isDirectory(url:URL) -> Bool? {
        var isDir: ObjCBool = ObjCBool(false)
        if fileExists(atPath: url.path, isDirectory: amp;isDir) {
            return isDir.boolValue
        } else {
            return nil
        }
    }
}