Переглядайте файли в папці та її підпапках за допомогою програми керування файлами Swift


76

Я зовсім новачок у програмуванні Swift і намагаюся переглядати файли в папці. Я подивився на відповідь тут і спробував перевести її на синтаксис Swift, але не вдалося.

let fileManager = NSFileManager.defaultManager()
let enumerator:NSDirectoryEnumerator = fileManager.enumeratorAtPath(folderPath)

for element in enumerator {
    //do something
}

я отримую помилку:

Type 'NSDirectoryEnumerator' does not conform to protocol 'SequenceType'

Моя мета - переглянути всі вкладені папки та файли, що містяться в головній папці, і знайти всі файли з певним розширенням, щоб потім щось з ними зробити.

Відповіді:


85

Використовуйте nextObject()метод enumerator:

while let element = enumerator?.nextObject() as? String {
    if element.hasSuffix("ext") { // checks the extension
    }
}

Не вдалося змусити це працювати без додаткового ланцюжка відповідно до відповіді користувача1398498 нижче.
Бьорн,

2
Щойно випробувавши це, я не отримав нічого, крім нескінченної петлі, і мені довелося приблизно піти з підходом Реньє.
nhgrif

Дуже дивно, що whileнад щільним forрозчином віддають перевагу досить сирій . (О, я бачу, я вже коментував інше рішення подібним чином - у будь-якому випадку)
qwerty_so

9
Для тих, хто використовує, enumerator(at:, includingPropertiesForKeys:, options:)враховуйте, що елемент насправді є URL-адресою, а не рядком, тому, якщо ви використовуєте цей код, він нічого не поверне. while let element = enumerator?.nextObject() as? URL {...}
Родріго Гонсалес

Хороша довідка. Я знайшов це за посиланням нижче. developer.apple.com/documentation/foundation/filemanager/…
arango_86

62

Сьогодні (на початку 2017 року) настійно рекомендується використовувати більш універсальний API, пов’язаний з URL-адресами

let fileManager = FileManager.default

do {
    let resourceKeys : [URLResourceKey] = [.creationDateKey, .isDirectoryKey]
    let documentsURL = try fileManager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
    let enumerator = FileManager.default.enumerator(at: documentsURL,
                            includingPropertiesForKeys: resourceKeys,
                                               options: [.skipsHiddenFiles], errorHandler: { (url, error) -> Bool in
                                                        print("directoryEnumerator error at \(url): ", error)
                                                        return true
    })!

    for case let fileURL as URL in enumerator {
        let resourceValues = try fileURL.resourceValues(forKeys: Set(resourceKeys))
        print(fileURL.path, resourceValues.creationDate!, resourceValues.isDirectory!)
    }
} catch {
    print(error)
}

Дякуємо за вашу ретельність. (Мені зовсім не пощастило з версією, набраною шляхом, оскільки myURL.absolutePath не є дійсним шляхом на основі рядків для цілей NSFileEnumerator і не створює дійсного перечислювача). Список URLResourceKeys див. На developer.apple.com/documentation/foundation/urlresourcekey
green_knight

Це хороший приклад того, як здійснити глибокий пошук і чудово працював для мене. Дякую за приємний внесок.
Buddhisthead

19

Я взагалі не міг отримати рішення pNre для роботи; цикл while просто нічого не отримував. Однак я натрапив на це рішення, яке працює для мене (у Xcode 6 beta 6, тому, можливо, все змінилося з тих пір, як pNre розмістив наведену вище відповідь?):

for url in enumerator!.allObjects {
    print("\((url as! NSURL).path!)")
}

1
Забавно, що це рішення має так мало голосів, оскільки воно має досить легший синтаксис, ніж поточний фаворит.
qwerty_so

2
причина, чому у нього є голоси, оскільки він покладається на примусове розгортання переписувача (перелічувача!) на відміну від перерахувача? у верхній частині проголосованої відповіді.
Борис Суворов

Остерігайтеся, що це непридатні для використання великі каталоги - вони можуть зависати хвилинами.
Абхі Беккерт

Зупиніть розгортання сили.
Марк Перкінс

9

повертає всі файли в каталозі + у підкаталогах

import Foundation

let path = "<some path>"

let enumerator = FileManager.default.enumerator(atPath: path)

while let filename = enumerator?.nextObject() as? String {
        print(filename)
}

2
Він не зайде в підкаталоги, не отримає приховані файли і не перейде за символічними посиланнями
vomi

як отримати повний шлях замість імен файлів?
ikel

Який шлях ви використовуєте? У моєму випадку у мене є каталог "mydir" у проекті xcode. Коли я використовую let path = "mydir", нічого не відбувається. Я використовую швидкий 5.
midtownguru

Це повний шлях. Чи є спосіб використовувати відносний шлях, щоб він містився в папці проекту?
midtownguru

8

Swift3 + абсолютні URL-адреси

extension FileManager {
    func listFiles(path: String) -> [URL] {
        let baseurl: URL = URL(fileURLWithPath: path)
        var urls = [URL]()
        enumerator(atPath: path)?.forEach({ (e) in
            guard let s = e as? String else { return }
            let relativeURL = URL(fileURLWithPath: s, relativeTo: baseurl)
            let url = relativeURL.absoluteURL
            urls.append(url)
        })
        return urls
    }
}

На основі коду @ user3441734


6

Стрімкий 3

let fd = FileManager.default
fd.enumerator(atPath: "/Library/FileSystems")?.forEach({ (e) in
    if let e = e as? String, let url = URL(string: e) {
        print(url.pathExtension)
    }
})

Коли я використав цей код, я виявив, що каталоги / файли з пробілами у шляху ігноруються. Будь-яка ідея, чому це відбувається? Потім я спробував код @ vadian, і він працює, як очікувалося.
ATutorMe


5

мої два центи від попередніх анвер .. більш швидкий і з необов'язковими:

 let enumerator = FileManager.default.enumerator(atPath: folderPath)
    while let element = enumerator?.nextObject() as? String {
        print(element)

        if let fType = enumerator?.fileAttributes?[FileAttributeKey.type] as? FileAttributeType{

            switch fType{
            case .typeRegular:
                print("a file")
            case .typeDirectory:
                print("a dir")
            }
        }

    }

Це ЦЕ найкорисніший запис тут, оскільки він підкреслює виділення записів за типами каталогів та файлів. Здається, це дуже забута частина такої функціональності.
ChrisH

4

SWIFT 3.0

Повертає всі файли з розширенням у переданій Директорії та її підкаталогах

func extractAllFile(atPath path: String, withExtension fileExtension:String) -> [String] {
    let pathURL = NSURL(fileURLWithPath: path, isDirectory: true)
    var allFiles: [String] = []
    let fileManager = FileManager.default
    let pathString = path.replacingOccurrences(of: "file:", with: "")
    if let enumerator = fileManager.enumerator(atPath: pathString) {
        for file in enumerator {
            if #available(iOS 9.0, *) {
                if let path = NSURL(fileURLWithPath: file as! String, relativeTo: pathURL as URL).path, path.hasSuffix(".\(fileExtension)"){
                    let fileNameArray = (path as NSString).lastPathComponent.components(separatedBy: ".")
                    allFiles.append(fileNameArray.first!)
                }
            } else {
                // Fallback on earlier versions
                print("Not available, #available iOS 9.0 & above")
            }
        }
    }
    return allFiles
}

2

Оновлення для Swift 3:

let fileManager = FileManager()     // let fileManager = NSFileManager.defaultManager()
let en=fileManager.enumerator(atPath: the_path)   // let enumerator:NSDirectoryEnumerator = fileManager.enumeratorAtPath(folderPath)

while let element = en?.nextObject() as? String {
    if element.hasSuffix("ext") {
        // do something with the_path/*.ext ....
    }
}

1

Додаючи до відповіді vadian - у документах Apple згадується, що URL-адреси на основі Шляху в чомусь простіші, проте посилання на URL-адреси файлів мають ту перевагу, що посилання залишається дійсним, якщо файл переміщено або перейменовано під час запуску програми.

З документації "Доступ до файлів і каталогів":

"URL-адресами, заснованими на шляху, легше маніпулювати, їх легше налагоджувати і, як правило, надають перевагу таким класам, як NSFileManager. Перевагою посилань на файли є те, що вони менш крихкі, ніж URL-адреси на основі шляхів під час роботи вашої програми. Якщо користувач працює переміщує файл у Finder, будь-які URL-адреси на основі шляху, які посилаються на файл, негайно стають недійсними і повинні бути оновлені до нового шляху. Однак, поки файл переміщується в інше місце на тому ж диску, його унікальний ідентифікатор не зміни, і будь-які посилання на файли залишаться дійсними "

https://developer.apple.com/library/content/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/AccessingFilesandDirectories/AccessingFilesandDirectories.html


0

Якщо ви хочете категорично перевірити, чи є елемент файлом чи підкаталогом:

let enumerator = FileManager.default.enumerator(atPath: contentsPath);
while let element = enumerator?.nextObject() as? String {             
   if(enumerator?.fileAttributes?[FileAttributeKey.type] as! FileAttributeType == FileAttributeType.typeRegular){
                //this is a file
   }
   else if(enumerator?.fileAttributes?[FileAttributeKey.type] as! FileAttributeType == FileAttributeType.typeDirectory){ 
                //this is a sub-directory
    }
}

0

Нещодавно боровся з цим при обробці масиву URL-адрес, незалежно від того, чи є вони каталогом чи ні (наприклад, перетягування та перетягування). Закінчене цим розширенням в швидкому 4, може бути корисним

extension Sequence where Iterator.Element == URL {

    var handleDir: [URL] {
        var files: [URL] = []
        self.forEach { u in
            guard u.hasDirectoryPath else { return files.append(u.resolvingSymlinksInPath()) }
            guard let dir = FileManager.default.enumerator(at: u.resolvingSymlinksInPath(), includingPropertiesForKeys: nil) else { return }
            for case let url as URL in dir {
                files.append(url.resolvingSymlinksInPath())
            }
        }
        return files
    }
}

-1

Уникайте посилань на URL-адреси, хоча вони мають деякі переваги, як зазначено вище, вони харчуються системними ресурсами, і якщо ви перелічуєте велику файлову систему (насправді не настільки велику), ваш додаток швидко потрапить у стіну системи і вимкне macOS.


Не відповідає на запитання, це має бути більше коментарем, ніж відповіддю.
TruMan1
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.