Directories in Swift

Here’s the translation of the Go code to Swift, formatted in Markdown suitable for Hugo:

Our first program will demonstrate working with directories in the file system. Here’s the full source code:

import Foundation

func check(_ error: Error?) {
    if let error = error {
        fatalError(error.localizedDescription)
    }
}

func main() {
    // Create a new sub-directory in the current working directory.
    do {
        try FileManager.default.createDirectory(atPath: "subdir", withIntermediateDirectories: false, attributes: nil)
    } catch {
        check(error)
    }

    // When creating temporary directories, it's good practice to defer their removal.
    defer {
        try? FileManager.default.removeItem(atPath: "subdir")
    }

    // Helper function to create a new empty file.
    let createEmptyFile = { (name: String) in
        FileManager.default.createFile(atPath: name, contents: nil, attributes: nil)
    }

    createEmptyFile("subdir/file1")

    // We can create a hierarchy of directories, including parents.
    do {
        try FileManager.default.createDirectory(atPath: "subdir/parent/child", withIntermediateDirectories: true, attributes: nil)
    } catch {
        check(error)
    }

    createEmptyFile("subdir/parent/file2")
    createEmptyFile("subdir/parent/file3")
    createEmptyFile("subdir/parent/child/file4")

    // List directory contents.
    do {
        let contents = try FileManager.default.contentsOfDirectory(atPath: "subdir/parent")
        print("Listing subdir/parent")
        for item in contents {
            let isDirectory = (try? FileManager.default.attributesOfItem(atPath: "subdir/parent/\(item)")[.type] as? FileAttributeType) == .typeDirectory
            print(" ", item, isDirectory)
        }
    } catch {
        check(error)
    }

    // Change the current working directory.
    FileManager.default.changeCurrentDirectoryPath("subdir/parent/child")

    // Now we'll see the contents of subdir/parent/child when listing the current directory.
    do {
        let contents = try FileManager.default.contentsOfDirectory(atPath: ".")
        print("Listing subdir/parent/child")
        for item in contents {
            let isDirectory = (try? FileManager.default.attributesOfItem(atPath: item)[.type] as? FileAttributeType) == .typeDirectory
            print(" ", item, isDirectory)
        }
    } catch {
        check(error)
    }

    // Change back to where we started.
    FileManager.default.changeCurrentDirectoryPath("../../..")

    // We can also visit a directory recursively, including all its sub-directories.
    print("Visiting subdir")
    visit(path: "subdir")
}

func visit(path: String) {
    do {
        let contents = try FileManager.default.contentsOfDirectory(atPath: path)
        for item in contents {
            let fullPath = (path as NSString).appendingPathComponent(item)
            var isDirectory: ObjCBool = false
            if FileManager.default.fileExists(atPath: fullPath, isDirectory: &isDirectory) {
                print(" ", fullPath, isDirectory.boolValue)
                if isDirectory.boolValue {
                    visit(path: fullPath)
                }
            }
        }
    } catch {
        print("Error while visiting \(path): \(error)")
    }
}

main()

This Swift code demonstrates various operations with directories:

  1. Creating directories
  2. Creating empty files
  3. Listing directory contents
  4. Changing the current working directory
  5. Recursively visiting a directory structure

To run this program, save it as Directories.swift and use the Swift compiler:

$ swift Directories.swift
Listing subdir/parent
  child true
  file2 false
  file3 false
Listing subdir/parent/child
  file4 false
Visiting subdir
  subdir/file1 false
  subdir/parent true
  subdir/parent/child true
  subdir/parent/child/file4 false
  subdir/parent/file2 false
  subdir/parent/file3 false

Note that Swift’s file system operations are performed using the FileManager class, which provides a more object-oriented approach compared to the C-style functions used in some other languages. The defer statement is used to ensure cleanup, similar to the original example. Error handling is done using Swift’s do-try-catch mechanism.