Obtendo a lista de arquivos na pasta de documentos

124

O que há de errado com meu código para obter os nomes de arquivos na pasta do documento?

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

Pensei ter lido os documentos corretamente e tenho certeza do que está na pasta de documentos, mas "fileList" não mostra nada? "dir" mostra o caminho para a pasta.

pawi
fonte
você deseja mostrar os nomes dos arquivos que estão no diretório de documentos ou também dos arquivos que estão nas pastas?
Adeel Ur Rehman
primeiro, apenas arquivos na própria pasta de documentos!
Pawi
Acabei de executar seu código e funcionou como esperado. Eu tenho uma lista do que está no meu diretório de documentos. Entendemos mal sua pergunta?
jwlaughton
Estranho? eu também usei ".fileExistsAtPath (path)", que indica que um arquivo específico está presente. Mas nada aparece em "fileList" !?
Pawi
Minha lista incluía diretórios e arquivos.
jwlaughton

Respostas:

111

Esta solução funciona com o Swift 4 (Xcode 9.2) e também com o 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)")
}

Aqui está uma extensão reutilizável do FileManager que também permite ignorar ou incluir arquivos ocultos nos 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
fonte
Como posso excluir arquivos 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
fonte
1
Para pessoas que são tão descuidadas quanto eu. Observe que a chamada: FileManager.default.contentsOfDirectory (atPath: <# T ## String #>) pode não funcionar corretamente por motivos desconhecidos no Swift 3.0. Use o indicado acima aqui.
Michael Shang
Se eu executar isso em um diretório do iCloud Drive, ele retornará apenas os itens que foram baixados para o dispositivo - existe alguma maneira de obter os URLs de todos os itens sem fazer o download primeiro?
mralexhay 9/04
@mralexhay mostra para mim até os itens que não são baixados. Ele deve mostrar um .prefixo de ponto e um .cloudsufixo no nome do arquivo. tente let icloudFiles = directoryContents.filter{ $0.pathExtension == "icloud" }deve mostrar os arquivos que não são baixados
Leo Dabus
1
@LeoDabus obrigado pela resposta - eu não tinha percebido que precede o ".", Pensei que tinha apenas o sufixo "iCloud". Percebi que não estava retornando arquivos ocultos - não é à toa que eles não apareceram! Obrigado novamente.
mralexhay 9/04
17

Uma sintaxe mais curta 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)
}

Exemplo de uso:

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

Testado no xCode 8.2.3 para iPhone 7 com iOS 10.2 e iPad com iOS 9.3

Nikita Kurtin
fonte
6

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

Você deve considerar o uso dos FileManagermétodos urls(for:in:)e url(for:in:appropriateFor:create:)quais URLs de retorno, que são o formato preferido.


Com o Swift 5, FileManagertem um método chamado contentsOfDirectory(at:includingPropertiesForKeys:options:). contentsOfDirectory(at:includingPropertiesForKeys:options:)tem a seguinte declaração:

Executa uma pesquisa superficial do diretório especificado e retorna URLs para os itens contidos.

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

Portanto, para recuperar os URLs dos arquivos contidos no diretório de documentos, você pode usar o seguinte snippet de código que usa FileManager's urls(for:in:)e contentsOfDirectory(at:includingPropertiesForKeys:options:)métodos:

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 exemplo, a UIViewControllerimplementação abaixo mostra como salvar um arquivo do pacote de aplicativos no diretório de documentos e como obter os URLs dos arquivos salvos no diretório 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
fonte
5

Este código imprime todos os diretórios e arquivos no meu diretório de documentos:

Alguma modificação de sua função:

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

Qual é chamado 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
fonte
4

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

    }

}

OU

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

Solução simples e 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
fonte