Better Swift FileManager File Existence Checks
I found the Foundation way to check for file existence very roundabout. It returns 1 boolean to indicate existence and you can have another boolean indicate if the item is a directory – passed by reference, like you used to in Objective-C land.
That’s a silent cry for an enum. So I created a simple wrapper that tells me what to expect at a given URL:
public enum FileExistence: Equatable {
case none
case file
case directory
}
public func ==(lhs: FileExistence, rhs: FileExistence) -> Bool {
switch (lhs, rhs) {
case (.none, .none),
(.file, .file),
(.directory, .directory):
return true
default: return false
}
}
extension FileManager {
public func existence(atUrl url: URL) -> FileExistence {
var isDirectory: ObjCBool = false
let exists = self.fileExists(atPath: url.path, isDirectory: &isDirectory)
switch (exists, isDirectory.boolValue) {
case (false, _): return .none
case (true, false): return .file
case (true, true): return .directory
}
}
}
And since you’re probably interested in well-tested components, here’re the unit tests:
class FileManager_ExistenceTests: XCTestCase {
func testExistence_NonExistingFile() {
let url = generatedTempFileURL()
XCTAssertEqual(FileManager.default.existence(atUrl: url), FileExistence.none)
}
func testExistence_ExistingFile() {
let url = generatedTempFileURL()
guard let _ = try? "some content".write(to: url, atomically: false, encoding: .utf8)
else { XCTFail("writing failed"); return }
XCTAssertEqual(FileManager.default.existence(atUrl: url), FileExistence.file)
}
func testExistence_ExistingDirectory() {
let url = createTempDirectory()
XCTAssertEqual(FileManager.default.existence(atUrl: url), FileExistence.directory)
}
}
… and here are the helper functions to create temporary files:
func createTempDirectory() -> URL {
let fileName = "filemanagertest-temp-dir.\(NSUUID().uuidString)"
let fileUrl = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(fileName)
try! FileManager.default.createDirectory(at: fileUrl, withIntermediateDirectories: false, attributes: nil)
return fileUrl
}
func generatedTempFileURL() -> URL {
let fileName = "filemanagertest-temp.\(NSUUID().uuidString)"
let fileURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(fileName)
return fileURL
}
If you happen to have a better name than existence(atUrl:)
come to mind, I’d be happy to change it!