Obtener una lista de archivos en la carpeta de documentos

124

¿Qué tiene de malo mi código para obtener los nombres de archivo en la carpeta de documentos?

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
    }
}

Pensé que había leído los documentos correctamente y estoy muy seguro de lo que hay en la carpeta de documentos, pero "fileList" no muestra nada. "dir" muestra la ruta a la carpeta.

pawi
fuente
¿Desea mostrar los nombres de los archivos que están en el directorio de documentos o también los archivos que están en las carpetas?
Adeel Ur Rehman
primero, ¡solo archivos en la carpeta de documentos!
pawi
Acabo de ejecutar su código y funcionó como se esperaba. Tengo una lista de lo que está en mi directorio de documentos. ¿No entendemos bien su pregunta?
jwlaughton
¿Extraño? También usé ".fileExistsAtPath (ruta)" que me dice que hay un archivo específico presente. ¿Pero nada aparece en "fileList"?
pawi
Mi lista incluía tanto directorios como archivos.
jwlaughton

Respuestas:

111

Esta solución funciona con Swift 4 (Xcode 9.2) y también con 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)")
}

Aquí hay una extensión reutilizable de FileManager que también le permite omitir o incluir archivos ocultos en los resultados:

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
fuente
¿Cómo puedo excluir archivos ocultos?
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
fuente
1
Para personas que son tan descuidadas como yo. Tenga en cuenta que la llamada: FileManager.default.contentsOfDirectory (atPath: <# T ## String #>) puede no funcionar correctamente por razones desconocidas en Swift 3.0. Use el que se da arriba aquí.
Michael Shang
Si ejecuto esto en un directorio de iCloud Drive, solo devuelve los elementos que se han descargado al dispositivo. ¿Hay alguna forma de obtener las URL de todos los elementos sin descargarlos primero?
mralexhay
@mralexhay me lo muestra incluso los elementos que no se descargan. Debería mostrar un .prefijo de punto y un .cloudsufijo en el nombre del archivo. intente let icloudFiles = directoryContents.filter{ $0.pathExtension == "icloud" }mostrar los archivos que no se descargan
Leo Dabus
1
@LeoDabus gracias por la respuesta: no me había dado cuenta de que antepone el ".", Pensé que solo tenía el sufijo "iCloud". Me di cuenta de que no estaba devolviendo archivos ocultos, ¡no es de extrañar que no aparecieran! Gracias de nuevo.
mralexhay
17

Una sintaxis más corta para 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)
}

Ejemplo de uso:

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

Probado en xCode 8.2.3 para iPhone 7 con iOS 10.2 y iPad con iOS 9.3

Nikita Kurtin
fuente
6

Apple declara sobre NSSearchPathForDirectoriesInDomains(_:_:_:):

Debe considerar el uso de los FileManagermétodos urls(for:in:)y url(for:in:appropriateFor:create:)las URL de retorno, que son el formato preferido.


Con Swift 5, FileManagertiene un método llamado contentsOfDirectory(at:includingPropertiesForKeys:options:). contentsOfDirectory(at:includingPropertiesForKeys:options:)tiene la siguiente declaración:

Realiza una búsqueda superficial del directorio especificado y devuelve URL para los elementos contenidos.

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

Por lo tanto, para recuperar las URL de los archivos contenidos en el directorio de documentos, puede usar el siguiente fragmento de código que usa FileManagerlos métodos urls(for:in:)y contentsOfDirectory(at:includingPropertiesForKeys:options:):

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)")
}

Como ejemplo, la UIViewControllerimplementación a continuación muestra cómo guardar un archivo del paquete de aplicaciones en el directorio de documentos y cómo obtener las URL de los archivos guardados en el directorio de documentos:

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
fuente
5

Este código imprime todos los directorios y archivos en mi directorio de documentos:

Alguna modificación de su función:

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
    }
}

Que se llama por:

    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
fuente
4

Compatibilidad con Swift 2.0

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)
       ........
        }

    }

}

O

 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
fuente
0

Solución simple y dinámica (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
fuente