Safely create a file if and only if it does not exist with Python
Edit: See also Dave Jones' answer: from Python 3.3, you can use the x
flag to open()
to provide this function.
Original answer below
Yes, but not using Python's standard open()
call. You'll need to use os.open()
instead, which allows you to specify flags to the underlying C code.
In particular, you want to use O_CREAT | O_EXCL
. From the man page for open(2)
under O_EXCL
on my Unix system:
So it's not perfect, but AFAIK it's the closest you can get to avoiding this race condition.Ensure that this call creates the file: if this flag is specified in conjunction with
O_CREAT
, and pathname already exists, thenopen()
will fail. The behavior ofO_EXCL
is undefined ifO_CREAT
is not specified.When these two flags are specified, symbolic links are not followed: if pathname is a symbolic link, then
open()
fails regardless of where the symbolic link points to.
O_EXCL
is only supported on NFS when using NFSv3 or later on kernel 2.6 or later. In environments where NFSO_EXCL
support is not provided, programs that rely on it for performing locking tasks will contain a race condition.
Edit: the other rules of using os.open()
instead of open()
still apply. In particular, if you want use the returned file descriptor for reading or writing, you'll need one of the O_RDONLY
, O_WRONLY
or O_RDWR
flags as well.
All the O_*
flags are in Python's os
module, so you'll need to import os
and use os.O_CREAT
etc.
Example:
import os
import errno
flags = os.O_CREAT | os.O_EXCL | os.O_WRONLY
try:
file_handle = os.open('filename', flags)
except OSError as e:
if e.errno == errno.EEXIST: # Failed as the file already exists.
pass
else: # Something unexpected went wrong so reraise the exception.
raise
else: # No exception, so the file must have been created successfully.
with os.fdopen(file_handle, 'w') as file_obj:
# Using `os.fdopen` converts the handle to an object that acts like a
# regular Python file object, and the `with` context manager means the
# file will be automatically closed when we're done with it.
file_obj.write("Look, ma, I'm writing to a new file!")
How can I safely create a directory (possibly including intermediate directories)?
On Python ≥ 3.5, use pathlib.Path.mkdir
:
from pathlib import Path
Path("/my/directory").mkdir(parents=True, exist_ok=True)
For older versions of Python, I see two answers with good qualities, each with a small flaw, so I will give my take on it:Try os.path.exists
, and consider os.makedirs
for the creation.
import os
if not os.path.exists(directory):
os.makedirs(directory)
As noted in comments and elsewhere, there's a race condition – if the directory is created between the os.path.exists
and the os.makedirs
calls, the os.makedirs
will fail with an OSError
. Unfortunately, blanket-catching OSError
and continuing is not foolproof, as it will ignore a failure to create the directory due to other factors, such as insufficient permissions, full disk, etc.One option would be to trap the OSError
and examine the embedded error code (see Is there a cross-platform way of getting information from Python’s OSError):
import os, errno
try:
os.makedirs(directory)
except OSError as e:
if e.errno != errno.EEXIST:
raise
Alternatively, there could be a second os.path.exists
, but suppose another created the directory after the first check, then removed it before the second one – we could still be fooled. Depending on the application, the danger of concurrent operations may be more or less than the danger posed by other factors such as file permissions. The developer would have to know more about the particular application being developed and its expected environment before choosing an implementation.
Modern versions of Python improve this code quite a bit, both by exposing FileExistsError
(in 3.3+)...
try:
os.makedirs("path/to/directory")
except FileExistsError:
# directory already exists
pass
...and by allowing a keyword argument to os.makedirs
called exist_ok
(in 3.2+).os.makedirs("path/to/directory", exist_ok=True) # succeeds even if directory exists.
Writing to a new file if it doesn't exist, and appending to a file if it does
It's not clear to me exactly where the high-score that you're interested in is stored, but the code below should be what you need to check if the file exists and append to it if desired. I prefer this method to the "try/except".
import os
player = 'bob'
filename = player+'.txt'
if os.path.exists(filename):
append_write = 'a' # append if already exists
else:
append_write = 'w' # make a new file if not
highscore = open(filename,append_write)
highscore.write("Username: " + player + '\n')
highscore.close()
How to have Python check if a file exists and create it if it doesn't?
Similar question
This is the best way:
try:
with open(filename) as file:
# do whatever
except IOError:
# generate the file
There's also os.path.exists(), but this can be a security concern. open() in Python does not create a file if it doesn't exist
You should use open
with the w+
mode:
file = open('myfile.dat', 'w+')
Create a file if it doesn't exist, otherwise do nothing
You can just catch the FileExistsError
and try opening the file with the exclusive creation mode.
open for exclusive creation, failing if the file already exists
def users_csv_file_init():
try:
with open("users.csv", 'x') as output_file:
writer = csv.writer(output_file)
writer.writerow(["userid", "username", "fname", "lname", "uuid"])
except FileExistsError:
pass
how to open (create if not exists) a file while acquiring exclusive lock avoiding races
No, it is not possible as a basic operation supported by Linux/UNIX.
The O_CREAT|O_EXCL technique in the answer you referenced can work here. Instead of exclusively creating the target file, you exclusively create a lockfile whose name is predictably derived from the target file. E.g., os.path.join("/tmp", hashlib.md5(target_filename).hexdigest() + ".lock")
.
However, as others have suggested, it's not clear that you need to protect both the target file creation and its checksumming + possible replacement. An fcntl
advisory lock will suit your needs.
Pythonic way to check if a file exists?
To check if a path is an existing file:
os.path.isfile(path)
Return
True
if path is an existing
regular file. This follows symbolic
links, so bothislink()
and
isfile()
can be true for the same
path.
Create file but if name exists add number
In a way, Python has this functionality built into the tempfile
module. Unfortunately, you have to tap into a private global variable, tempfile._name_sequence
. This means that officially, tempfile
makes no guarantee that in future versions _name_sequence
even exists -- it is an implementation detail.
But if you are okay with using it anyway, this shows how you can create uniquely named files of the form file#.pdf
in a specified directory such as /tmp
:
import tempfile
import itertools as IT
import os
def uniquify(path, sep = ''):
def name_sequence():
count = IT.count()
yield ''
while True:
yield '{s}{n:d}'.format(s = sep, n = next(count))
orig = tempfile._name_sequence
with tempfile._once_lock:
tempfile._name_sequence = name_sequence()
path = os.path.normpath(path)
dirname, basename = os.path.split(path)
filename, ext = os.path.splitext(basename)
fd, filename = tempfile.mkstemp(dir = dirname, prefix = filename, suffix = ext)
tempfile._name_sequence = orig
return filename
print(uniquify('/tmp/file.pdf'))
Related Topics
How to Log a Python Error with Debug Information
How to Change Data Points Color Based on Some Variable
How to Read a File Line-By-Line in Python
How to Get the Version Defined in Setup.Py (Setuptools) in My Package
In Python, What Happens When You Import Inside of a Function
How to Check Task Status in Celery
Why How to Not Create a Wheel in Python
Python Pandas Dataframe, Is It Pass-By-Value or Pass-By-Reference
How Do Threads Work in Python, and What Are Common Python-Threading Specific Pitfalls
How to Get a Gcp Bearer Token Programmatically with Python
Shell Script: Execute a Python Program from Within a Shell Script
Using Only the Db Part of Django
Recursive List Comprehension in Python
Counting Letter Frequency in a String (Python)
Most Efficient Way to Sort an Array into Bins Specified by an Index Array