Skip to content

Instantly share code, notes, and snippets.

@kristopherjohnson
Last active November 29, 2023 12:32
Show Gist options
  • Save kristopherjohnson/4bafee0b489add42a61f to your computer and use it in GitHub Desktop.
Save kristopherjohnson/4bafee0b489add42a61f to your computer and use it in GitHub Desktop.
Example of using opendir/readdir/closedir with Swift
import Foundation
// Get current working directory
var wdbuf: [Int8] = Array(count: Int(MAXNAMLEN), repeatedValue: 0)
let workingDirectory = getcwd(&wdbuf, UInt(MAXNAMLEN))
println("Working directory: \(String.fromCString(workingDirectory)!)")
println("\nContents:")
// Open the directory
let dir = opendir(workingDirectory)
if dir != nil {
// Use readdir to get each element
var entry = readdir(dir)
while entry != nil {
let d_namlen = entry.memory.d_namlen
let d_name = entry.memory.d_name
// dirent.d_name is defined as a tuple with
// MAXNAMLEN elements. We want to convert
// that to a null-terminated C string. The
// only way to iterate over tuple elements
// in Swift is via reflection.
//
// Credit: dankogi at http://stackoverflow.com/questions/24299045/any-way-to-iterate-a-tuple-in-swift
var nameBuf: [CChar] = Array()
let mirror = reflect(d_name)
for i in 0..<d_namlen {
let (_, elem) = mirror[Int(i)]
nameBuf.append(elem.value as Int8)
}
// Null-terminate it and convert to a String for display
nameBuf.append(0)
if let name = String.fromCString(nameBuf) {
println("- \(name)")
}
entry = readdir(dir)
}
closedir(dir)
}
@josipbernat
Copy link

This is a similar version of this code adopted to Swift 5.9. It excludes ".", ".." and similar files because I find them useless. Also it returns [URL] instead of [String].

extension FileManager {
    
    func contentsOfDirectoryUsingCAPI(url: URL) -> [URL]? {
        guard let folderPathCString = url.path.cString(using: .utf8) else {
            return nil
        }

        // Open the directory
        guard let dir = opendir(folderPathCString) else {
            return nil
        }

        var contentsOfDirectory = [URL]()

        // Use readdir to get each element
        while let entry = readdir(dir) {
            let d_namlen = Int(entry.pointee.d_namlen)
            let d_name = withUnsafePointer(to: &entry.pointee.d_name) {
                $0.withMemoryRebound(to: CChar.self, capacity: d_namlen) { ptr in
                    String(cString: ptr)
                }
            }

            if !d_name.allSatisfy({ $0 == "." }) {
                let fileURL = url.appendingPathComponent(d_name)
                contentsOfDirectory.append(fileURL)
            }
        }

        closedir(dir)

        return contentsOfDirectory
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment