Skip to main content

Writing a file in Swift, but only if it doesn’t already exist

Adding Data.WritingOptions.withoutOverwriting to your write() call will prevent you from overwriting a file that already exists.

In Python I’m fairly used to the idea of using file mode x to do an “exclusive” file open. This allows you to write to a file, but only if it doesn’t already exist. In this example, if greeting.txt already exists, the open() call will throw a FileExistsError.

with open("greeting.txt", "x") as f:
    f.write("Hello world")

How can I do the same in Swift?

Let’s start with a simple Swift script that runs the current date to a file:

import Foundation

let now = Date()
let data: Data = "\(now)\n".data(using: .utf8)!

let savePath = URL(fileURLWithPath: "now.txt")

do {
  try data.write(to: savePath)
} catch {
  print("Unable to write data: \(error.localizedDescription)")
}

And if I run it twice, the second run will overwrite the file created by the first run:

$ swift write_date.swift ; cat now.txt
2024-05-16 14:05:04 +0000

$ swift write_date.swift ; cat now.txt
2024-05-16 14:05:18 +0000

What if I want to ensure a file never gets overwritten?

It turns out you can pass a list of options to the write() call, which is a list of Data.WritingOptions values. This is an alias for NSData.WritingOptions. One of the options is withoutOverwriting, which will fail if the file you’re trying to write to already exists:

do {
  try data.write(
    to: savePath,
    options: [Data.WritingOptions.withoutOverwriting]
  )
} catch {
  print("Unable to write data: \(error.localizedDescription)")
}

If I run the new script twice, the second run will fail with an error that I can catch and react to:

$ swift write_date2.swift; cat now.txt
2024-05-16 14:07:38 +0000

$ swift write_date2.swift
Unable to write data: The file “now.txt” couldn’t be saved in the folder
“tmp.QYW2iXbbmt” because a file with the same name already exists.

There are a couple of other interesting values in NSData.WritingOptions. The one I’m mostly likely to use is atomic (for atomic write). There are also a couple of options related to encryption and file access that I don’t really understand – I think I’m missing some context for the security approach here.