Liste der Dateien im Dokumentenordner abrufen

124

Was ist falsch an meinem Code zum Abrufen der Dateinamen im Dokumentordner?

func listFilesFromDocumentsFolder() -> [NSString]?{
    var theError = NSErrorPointer()
    let dirs = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.AllDomainsMask, true) as? [String]
    if dirs != nil {
        let dir = dirs![0] as NSString
        let fileList = NSFileManager.defaultManager().contentsOfDirectoryAtPath(dir, error: theError) as [NSString]
        return fileList
    }else{
        return nil
    }
}

Ich dachte, ich hätte die Dokumente richtig gelesen und bin mir sehr sicher, was sich im Dokumentenordner befindet, aber "fileList" zeigt nichts an? "dir" zeigt den Pfad zum Ordner.

Pawi
quelle
Sie möchten die Namen der Dateien anzeigen, die sich im Dokumentverzeichnis befinden, oder die Dateien, die sich auch in den Ordnern befinden?
Adeel Ur Rehman
Erstens nur Dateien im Dokumentordner selbst!
Pawi
Ich habe gerade Ihren Code ausgeführt und es hat wie erwartet funktioniert. Ich habe eine Liste der Dokumente in meinem Dokumentenverzeichnis. Verstehen wir Ihre Frage falsch?
Jwlaughton
Seltsam? Ich habe auch ".fileExistsAtPath (Pfad)" verwendet, was mir sagt, dass eine bestimmte Datei vorhanden ist. Aber in "fileList" wird nichts angezeigt!?
Pawi
Meine Liste enthielt sowohl Verzeichnisse als auch Dateien.
Jwlaughton

Antworten:

111

Diese Lösung funktioniert mit Swift 4 (Xcode 9.2) und auch mit Swift 5 (Xcode 10.2.1+):

let fileManager = FileManager.default
let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
do {
    let fileURLs = try fileManager.contentsOfDirectory(at: documentsURL, includingPropertiesForKeys: nil)
    // process files
} catch {
    print("Error while enumerating files \(documentsURL.path): \(error.localizedDescription)")
}

Hier ist eine wiederverwendbare FileManager-Erweiterung, mit der Sie auch versteckte Dateien überspringen oder in die Ergebnisse aufnehmen können:

import Foundation

extension FileManager {
    func urls(for directory: FileManager.SearchPathDirectory, skipsHiddenFiles: Bool = true ) -> [URL]? {
        let documentsURL = urls(for: directory, in: .userDomainMask)[0]
        let fileURLs = try? contentsOfDirectory(at: documentsURL, includingPropertiesForKeys: nil, options: skipsHiddenFiles ? .skipsHiddenFiles : [] )
        return fileURLs
    }
}

// Usage
print(FileManager.default.urls(for: .documentDirectory) ?? "none")
Karoly Nyisztor
quelle
Wie kann ich versteckte Dateien ausschließen?
BasedMusa
251

Swift 5

// Get the document directory url
let documentsUrl =  FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!

do {
    // Get the directory contents urls (including subfolders urls)
    let directoryContents = try FileManager.default.contentsOfDirectory(at: documentsUrl, includingPropertiesForKeys: nil)
    print(directoryContents)

    // if you want to filter the directory contents you can do like this:
    let mp3Files = directoryContents.filter{ $0.pathExtension == "mp3" }
    print("mp3 urls:",mp3Files)
    let mp3FileNames = mp3Files.map{ $0.deletingPathExtension().lastPathComponent }
    print("mp3 list:", mp3FileNames)

} catch {
    print(error)
}
Leo Dabus
quelle
1
Für Menschen, die so nachlässig sind wie ich. Beachten Sie, dass der Aufruf: FileManager.default.contentsOfDirectory (atPath: <# T ## String #>) in Swift 3.0 aus unbekannten Gründen möglicherweise nicht ordnungsgemäß funktioniert. Verwenden Sie die oben angegebene.
Michael Shang
Wenn ich dies in einem iCloud Drive-Verzeichnis ausführe, werden nur Elemente zurückgegeben, die auf das Gerät heruntergeladen wurden. Gibt es eine Möglichkeit, die URLs aller Elemente abzurufen, ohne sie zuerst herunterzuladen?
Mralexhay
@mralexhay es zeigt mir für mich auch die Artikel, die nicht heruntergeladen werden. Es sollte ein Punktpräfix .und ein .cloudSuffix im Dateinamen enthalten. versuchen Sie let icloudFiles = directoryContents.filter{ $0.pathExtension == "icloud" }es sollte die Dateien
anzeigen
1
@LeoDabus danke für die Antwort - ich hatte nicht bemerkt, dass das "." Vorangestellt ist, ich dachte, es hätte nur das Suffix "iCloud". Mir wurde klar, dass ich keine versteckten Dateien zurückgab - kein Wunder, dass sie nicht angezeigt wurden! Danke noch einmal.
Mralexhay
17

Eine kürzere Syntax für SWIFT 3

func listFilesFromDocumentsFolder() -> [String]?
{
    let fileMngr = FileManager.default;

    // Full path to documents directory
    let docs = fileMngr.urls(for: .documentDirectory, in: .userDomainMask)[0].path

    // List all contents of directory and return as [String] OR nil if failed
    return try? fileMngr.contentsOfDirectory(atPath:docs)
}

Anwendungsbeispiel:

override func viewDidLoad()
{
    print(listFilesFromDocumentsFolder())
}

Getestet auf xCode 8.2.3 für iPhone 7 mit iOS 10.2 und iPad mit iOS 9.3

Nikita Kurtin
quelle
6

Apple sagt über NSSearchPathForDirectoriesInDomains(_:_:_:):

Sie sollten in Betracht ziehen, die FileManagerMethoden zu verwenden urls(for:in:)und url(for:in:appropriateFor:create:)die URLs zurückzugeben, die das bevorzugte Format sind.


Mit Swift 5 FileManagerwird eine Methode aufgerufen contentsOfDirectory(at:includingPropertiesForKeys:options:). contentsOfDirectory(at:includingPropertiesForKeys:options:)hat die folgende Erklärung:

Führt eine flache Suche im angegebenen Verzeichnis durch und gibt URLs für die enthaltenen Elemente zurück.

func contentsOfDirectory(at url: URL, includingPropertiesForKeys keys: [URLResourceKey]?, options mask: FileManager.DirectoryEnumerationOptions = []) throws -> [URL]

Um die URLs der im Dokumentenverzeichnis enthaltenen Dateien abzurufen, können Sie daher das folgende Codefragment verwenden FileManager, das s urls(for:in:)und contentsOfDirectory(at:includingPropertiesForKeys:options:)Methoden verwendet:

guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }

do {
    let directoryContents = try FileManager.default.contentsOfDirectory(at: documentsDirectory, includingPropertiesForKeys: nil, options: [])

    // Print the urls of the files contained in the documents directory
    print(directoryContents)
} catch {
    print("Could not search for urls of files in documents directory: \(error)")
}

Die folgende UIViewControllerImplementierung zeigt beispielhaft, wie eine Datei aus dem App-Bundle im Dokumentenverzeichnis gespeichert wird und wie die URLs der im Dokumentenverzeichnis gespeicherten Dateien abgerufen werden:

import UIKit

class ViewController: UIViewController {

    @IBAction func copyFile(_ sender: UIButton) {
        // Get file url
        guard let fileUrl = Bundle.main.url(forResource: "Movie", withExtension: "mov") else { return }

        // Create a destination url in document directory for file
        guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
        let documentDirectoryFileUrl = documentsDirectory.appendingPathComponent("Movie.mov")

        // Copy file to document directory
        if !FileManager.default.fileExists(atPath: documentDirectoryFileUrl.path) {
            do {
                try FileManager.default.copyItem(at: fileUrl, to: documentDirectoryFileUrl)
                print("Copy item succeeded")
            } catch {
                print("Could not copy file: \(error)")
            }
        }
    }

    @IBAction func displayUrls(_ sender: UIButton) {
        guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }

        do {
            let directoryContents = try FileManager.default.contentsOfDirectory(at: documentsDirectory, includingPropertiesForKeys: nil, options: [])

            // Print the urls of the files contained in the documents directory
            print(directoryContents) // may print [] or [file:///private/var/mobile/Containers/Data/Application/.../Documents/Movie.mov]
        } catch {
            print("Could not search for urls of files in documents directory: \(error)")
        }
    }

}
Imanou Petit
quelle
5

Dieser Code druckt alle Verzeichnisse und Dateien in meinem Dokumentenverzeichnis aus:

Einige Änderungen Ihrer Funktion:

func listFilesFromDocumentsFolder() -> [String]
{
    let dirs = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.allDomainsMask, true)
    if dirs != [] {
        let dir = dirs[0]
        let fileList = try! FileManager.default.contentsOfDirectory(atPath: dir)
        return fileList
    }else{
        let fileList = [""]
        return fileList
    }
}

Welches wird aufgerufen von:

    let fileManager:FileManager = FileManager.default
    let fileList = listFilesFromDocumentsFolder()

    let count = fileList.count

    for i in 0..<count
    {
        if fileManager.fileExists(atPath: fileList[i]) != true
        {
            print("File is \(fileList[i])")
        }
    }
jwlaughton
quelle
4

Swift 2.0-Kompatibilität

func listWithFilter () {

    let fileManager = NSFileManager.defaultManager()
           // We need just to get the documents folder url
    let documentsUrl = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0] as NSURL

    do {
    // if you want to filter the directory contents you can do like this:
    if let directoryUrls = try? NSFileManager.defaultManager().contentsOfDirectoryAtURL(documentsUrl, includingPropertiesForKeys: nil, options: NSDirectoryEnumerationOptions.SkipsSubdirectoryDescendants) {
        print(directoryUrls)
       ........
        }

    }

}

ODER

 func listFiles() -> [String] {

    var theError = NSErrorPointer()
    let dirs = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.AllDomainsMask, true) as? [String]
    if dirs != nil {
        let dir = dirs![0]
        do {
        let fileList = try NSFileManager.defaultManager().contentsOfDirectoryAtPath(dir)
        return fileList as [String]
        }catch {

        }

    }else{
        let fileList = [""]
        return fileList
    }
    let fileList = [""]
    return fileList

}
Gleb
quelle
0

Einfache und dynamische Lösung (Swift 5):

extension FileManager {

  class func directoryUrl() -> URL? {
      let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
      return paths.first
  }

  class func allRecordedData() -> [URL]? {
     if let documentsUrl = FileManager.directoryUrl() {
        do {
            let directoryContents = try FileManager.default.contentsOfDirectory(at: documentsUrl, includingPropertiesForKeys: nil)
            return directoryContents.filter{ $0.pathExtension == "m4a" }
        } catch {
            return nil
        }
     }
     return nil
  }}
nitin.agam
quelle