How do you read and write files safely, and why is fileExists-then-act a bug?
Predict first
What does this print?
do {
try FileManager.default.removeItem(at: URL(fileURLWithPath: "/tmp/definitely-missing-file"))
} catch {
print((error as? CocoaError)?.code == .fileNoSuchFile)
}
- true
- false
- Nothing
Predict first
What does this print?
let dir = FileManager.default.temporaryDirectory.appending(path: "p-\(UUID())/a/b")
do {
try FileManager.default.createDirectory(at: dir, withIntermediateDirectories: false)
print("created")
} catch {
print("threw")
}
- created
- threw
Mental model. Atomic writing is preparing the new page on a separate sheet and then swapping it in, so the book is never torn open halfway.
Write with data.write(to:options: .atomic): it writes a temporary file and renames it into place, so a crash never leaves a half-written file. Read small files with Data(contentsOf:), big ones with .mappedIfSafe or a FileHandle that reads chunks. Failures arrive as errors, typically CocoaError with a code like .fileNoSuchFile.
Do not check fileExists and then act: the file can change in between (a time-of-check/time-of-use race). Just try the operation and handle the error. createDirectory(withIntermediateDirectories: true) succeeds if the folder already exists and builds missing parents; with false it throws if a parent is missing. For iCloud or shared files use NSFileCoordinator.
Removing something that is not there throws a CocoaError with .fileNoSuchFile. It does not silently succeed.
With withIntermediateDirectories: false, a missing parent is an error. Pass true to build the whole chain.
Common traps
fileExiststhenremoveItem. Two steps, one race. CallremoveItemand catch.fileNoSuchFile.- Reading a huge file into memory at once. Map it or stream it.
They might follow up with
- Does
.atomicprotect against concurrent writers? No. It protects against torn writes, not two writers overwriting each other. - How do you protect a file at rest? Pass a data protection option such as
.completeFileProtection.
Related questions
- 2.3.5 What is Data, and how do you convert it to and from text?
- 2.3.6 Where should an iOS app put files: Documents, Application Support, Caches or tmp?
← Where should an iOS app put files: Documents, Application Support…