รับรายชื่อไฟล์ในโฟลเดอร์เอกสาร


124

เกิดอะไรขึ้นกับรหัสของฉันในการรับชื่อไฟล์ในโฟลเดอร์เอกสาร

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

ฉันคิดว่าฉันอ่านเอกสารอย่างถูกต้องและฉันมั่นใจมากเกี่ยวกับสิ่งที่อยู่ในโฟลเดอร์เอกสาร แต่ "fileList" ไม่แสดงอะไรเลย? "dir" แสดงเส้นทางไปยังโฟลเดอร์


คุณต้องการแสดงชื่อของไฟล์ที่อยู่ในไดเร็กทอรีเอกสารหรือไฟล์ที่อยู่ในโฟลเดอร์ด้วยหรือไม่?
Adeel Ur Rehman

อันดับแรกเฉพาะไฟล์ในโฟลเดอร์เอกสารเท่านั้น!
pawi

ฉันเพิ่งรันโค้ดของคุณและทำงานได้ตามที่คาดไว้ ฉันได้รับรายการสิ่งที่อยู่ในไดเรกทอรีเอกสารของฉัน เราเข้าใจผิดคำถามของคุณหรือไม่?
jwlaughton

แปลก? ฉันยังใช้ ".fileExistsAtPath (path)" ซึ่งบอกว่ามีไฟล์เฉพาะอยู่ แต่ไม่มีอะไรปรากฏใน "fileList"!?
pawi

รายการของฉันมีทั้งไดเร็กทอรีและไฟล์
jwlaughton

คำตอบ:


112

โซลูชันนี้ใช้ได้กับSwift 4 (Xcode 9.2) และ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)")
}

นี่คือส่วนขยาย FileManager ที่ใช้ซ้ำได้ซึ่งให้คุณข้ามหรือรวมไฟล์ที่ซ่อนไว้ในผลลัพธ์:

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

ฉันจะยกเว้นไฟล์ที่ซ่อนอยู่ได้อย่างไร
BasedMusa

251

สวิฟต์ 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)
}

1
สำหรับคนที่มักง่ายอย่างฉัน โปรดทราบว่าการเรียก: FileManager.default.contentsOfDirectory (atPath: <# T ## String #>) อาจทำงานไม่ถูกต้องเนื่องจากไม่ทราบสาเหตุใน Swift 3.0 ใช้สิ่งที่ระบุไว้ด้านบนที่นี่
Michael Shang

หากฉันเรียกใช้สิ่งนี้บนไดเร็กทอรี iCloud Drive ระบบจะส่งคืนเฉพาะรายการที่ดาวน์โหลดไปยังอุปกรณ์เท่านั้นมีวิธีใดบ้างในการรับ URL ของรายการทั้งหมดโดยไม่ต้องดาวน์โหลดก่อน
mralexhay

@mralexhay มันแสดงให้ฉันเห็นแม้กระทั่งรายการที่ไม่ได้ดาวน์โหลด ควรแสดง.คำนำหน้าจุดและ.cloudคำต่อท้ายในชื่อไฟล์ ลองlet icloudFiles = directoryContents.filter{ $0.pathExtension == "icloud" }ใช้ควรแสดงไฟล์ที่ไม่ได้ดาวน์โหลด
Leo Dabus

1
@LeoDabus ขอบคุณสำหรับการตอบกลับ - ฉันไม่รู้ว่ามันขึ้นต้น "." ฉันคิดว่ามันมีคำต่อท้าย "iCloud" ฉันรู้ว่าฉันไม่ได้ส่งคืนไฟล์ที่ซ่อนอยู่ - ไม่น่าแปลกใจเลยที่มันไม่แสดง! ขอบคุณอีกครั้ง.
mralexhay

17

ไวยากรณ์ที่สั้นกว่าสำหรับ 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)
}

ตัวอย่างการใช้งาน:

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

ทดสอบบน xCode 8.2.3 สำหรับ iPhone 7 ที่ใช้ iOS 10.2 และ iPad พร้อม iOS 9.3


6

Apple ระบุเกี่ยวกับNSSearchPathForDirectoriesInDomains(_:_:_:):

คุณควรพิจารณาใช้FileManagerวิธีการurls(for:in:)และurl(for:in:appropriateFor:create:)URL ที่ส่งคืนซึ่งเป็นรูปแบบที่ต้องการ


ด้วย Swift 5 FileManagerมีวิธีการที่เรียกว่าcontentsOfDirectory(at:includingPropertiesForKeys:options:). contentsOfDirectory(at:includingPropertiesForKeys:options:)มีประกาศดังต่อไปนี้:

ทำการค้นหาแบบตื้นของไดเร็กทอรีที่ระบุและส่งคืน URL สำหรับไอเท็มที่มีอยู่

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

ดังนั้นเพื่อที่จะดึง URL ของไฟล์ที่มีอยู่ในไดเรกทอรีเอกสารคุณสามารถใช้โค้ดต่อไปนี้ที่ใช้FileManager's urls(for:in:)และ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)")
}

ตัวอย่างการUIViewControllerใช้งานด้านล่างแสดงวิธีบันทึกไฟล์จาก App Bundle ไปยังไดเร็กทอรีเอกสารและวิธีรับ URL ของไฟล์ที่บันทึกในไดเร็กทอรีเอกสาร:

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

}

5

รหัสนี้พิมพ์ไดเร็กทอรีและไฟล์ทั้งหมดในไดเร็กทอรีเอกสารของฉัน:

การปรับเปลี่ยนฟังก์ชันบางอย่างของคุณ:

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

ซึ่งเรียกโดย:

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

4

ความเข้ากันได้ของ 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)
       ........
        }

    }

}

หรือ

 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

}

0

โซลูชันที่เรียบง่ายและมีไดนามิก (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
  }}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.