Cross-platform file system utilities for Apple platforms — directory enumeration, recursive directory observation, extended attributes, and macOS Finder tag management.
- Platforms: macOS 13+, iOS 16+
- Swift: 6.2+
dependencies: [
.package(url: "https://github.com/ryanfrancesconi/spfk-filesystem", from: "0.0.1"),
]Then add SPFKFileSystem to your target's dependencies:
.target(
name: "MyTarget",
dependencies: [
.product(name: "SPFKFileSystem", package: "spfk-filesystem"),
]
)| Type / Extension | macOS | iOS |
|---|---|---|
FileSystem |
Y | Y |
DirectoryObserver |
Y | Y |
DirectoryEnumerationObserver |
Y | Y |
DirectoryEvent |
Y | Y |
URL xattr extensions |
Y | Y |
FSEventsDirectoryObserver |
Y | — |
SecureURLRegistry |
Y | — |
TagColor |
Y | — |
FinderTagDescription |
Y | — |
FinderTagGroup |
Y | — |
URL Finder tag extensions |
Y | — |
Two strategies for monitoring a directory tree for file additions and deletions. Both produce DirectoryEvent values (.new / .removed) delivered through DirectoryEnumerationObserverDelegate.
DirectoryEnumerationObserver creates one DirectoryObserver per subdirectory, each backed by a file descriptor and DispatchSource. Works on all Apple platforms but consumes one file descriptor per monitored subdirectory.
let observer = try DirectoryEnumerationObserver(url: directoryURL, delegate: self)
try await observer.start()
// ...
await observer.stop()FSEventsDirectoryObserver uses a single CoreServices FSEventStream to monitor an entire directory tree recursively. More efficient for large hierarchies — no per-directory file descriptors.
let observer = try FSEventsDirectoryObserver(url: directoryURL, delegate: self)
await observer.start()
// ...
await observer.stop()DirectoryEnumerationObserver |
FSEventsDirectoryObserver |
|
|---|---|---|
| Platform | All Apple platforms | macOS only |
| Underlying API | kqueue (DispatchSource) |
CoreServices FSEventStream |
| Resources | 1 file descriptor per subdirectory | 1 stream total |
| Recursive | Via ObservationData coordination |
Built-in |
start() |
async throws |
Non-throwing |
| Event source URL | Per-subdirectory | Root URL only |
FileSystem provides static methods for common operations:
- Disk space —
freeSpace(forPath:),totalSpace(forPath:),freeSpaceDescription(forPath:),totalSpaceDescription(forPath:) - Volumes —
mountedVolumes(),volumeURL(forFileURL:) - File enumeration —
enumerateFiles(in:...),enumerateDirectories(in:...),enumeratePackages(in:...) - Search —
findDirectory(named:in:) - Streaming —
fileURLStream(in:) - Path utilities —
nextAvailableURL(_:) - Cleanup —
deleteEmptyDirectories(in:)
Read and write macOS Finder color labels and custom text tags via extended attributes.
// Read tags
let tagColors = fileURL.tagColors // [TagColor]
let tagNames = fileURL.tagNames // [String]
let tags = fileURL.finderTags // [FinderTagDescription]
// Write tags
try fileURL.set(tagColors: [.red, .blue])
try fileURL.set(finderTags: tagGroup)
try fileURL.removeAllTags()TagColor represents the 7 built-in Finder label colors (gray, green, purple, blue, yellow, red, orange) plus .none. FinderTagDescription pairs a color with a label string and also supports custom text-only tags. FinderTagGroup collects multiple tag descriptions for batch operations.
SecureURLRegistry manages startAccessingSecurityScopedResource() / stopAccessingSecurityScopedResource() lifecycle for sandboxed apps. Duplicate access calls for the same URL are automatically deduplicated to prevent unbalanced reference counts.
let registry = SecureURLRegistry()
let (url, isStale) = try await registry.create(resolvingBookmarkData: bookmarkData)
// ... use url ...
await registry.release(url: url) // release individual URL when done
await registry.releaseAll() // or release all on app shutdown- spfk-base — logging and base utilities
- swift-extensions — Swift standard library extensions
- swift-xattr — extended attribute read/write
Copyright Ryan Francesconi. All Rights Reserved.
Spongefork (SPFK) is the personal software projects of Ryan Francesconi. Dedicated to creative sound manipulation, his first application, Spongefork, was released in 1999 for macOS 8. From 2016 to 2025 he was the lead macOS developer at Audio Design Desk.