ryanfrancesconi/spfk-filesystem
Cross-platform file system utilities for Apple platforms — directory enumeration, recursive directory observation, extended attributes, and macOS Finder tag management.
Requirements
- Platforms: macOS 13+, iOS 16+
- Swift: 6.2+
Installation
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"),
]
)Platform Availability
| 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 | — |
Directory Observation
Two strategies for monitoring a directory tree for file additions and deletions. Both produce DirectoryEvent values (.new / .removed) delivered through DirectoryEnumerationObserverDelegate.
kqueue (cross-platform)
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()FSEvents (macOS only)
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 |
File System Utilities
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:)
Security-Scoped Bookmarks (macOS)
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 shutdownDependencies
- spfk-base — logging and base utilities
- swift-extensions — Swift standard library extensions
- swift-xattr — extended attribute read/write
License
Copyright Ryan Francesconi. All Rights Reserved.
About
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.
Package Metadata
Repository: ryanfrancesconi/spfk-filesystem
Default branch: main
README: README.md