Does Python have any built-in functionality to add a number to a filename if it already exists?
My idea is that it would work the way certain OS\'s work - if a file
I ended up writing my own simple function for this. Primitive, but gets the job done:
def uniquify(path):
filename, extension = os.path.splitext(path)
counter = 1
while os.path.exists(path):
path = filename + " (" + str(counter) + ")" + extension
counter += 1
return path
A great solution is to use a function that takes 2 arguments and returns the first non-existed filename available. On the first iteration, the function tries to check if filename without any number exists. If this filename is already taken, the function tries to apply a number 0
right before the file extension. If this filename is already taken too, the function adds +1
to this number until non-existed filename will be found.
import os
def unique_filename(output_filename, file_extension):
n = ''
while os.path.exists(f'{output_filename}{n}{file_extension}'):
if isinstance(n, str):
n = -1
n += 1
return f'{output_filename}{n}{file_extension}'
import os
def unique_filename(output_filename, file_extension):
n = ''
while os.path.exists('%s%s%s' % (output_filename, n, file_extension)):
if isinstance(n, str):
n = -1
n += 1
return '%s%s%s' % (output_filename, n, file_extension)
file_path will be split into file path with filename
and file extension
(f.e. ".jpg")
import os
def unique_filename_path(file_path):
output_filename, file_extension = os.path.splitext(file_path)
n = ''
while os.path.exists(f'{output_filename}{n}{file_extension}'):
if isinstance(n, str):
n = -1
n += 1
return f'{output_filename}{n}{file_extension}'
If all files being numbered isn't a problem, and you know beforehand the name of the file to be written, you could simply do:
import os
counter = 0
filename = "file{}.pdf"
while os.path.isfile(filename.format(counter)):
counter += 1
filename = filename.format(counter)
import os
class Renamer():
def __init__(self, name):
self.extension = name.split('.')[-1]
self.name = name[:-len(self.extension)-1]
self.filename = self.name
def rename(self):
i = 1
if os.path.exists(self.filename+'.'+self.extension):
while os.path.exists(self.filename+'.'+self.extension):
self.filename = '{} ({})'.format(self.name,i)
i += 1
return self.filename+'.'+self.extension
Since the tempfile hack A) is a hack and B) still requires a decent amount of code anyway, I went with a manual implementation. You basically need:
I defined a safe_open that can be used just like open:
def iter_incrementing_file_names(path):
"""
Iterate incrementing file names. Start with path and add " (n)" before the
extension, where n starts at 1 and increases.
:param path: Some path
:return: An iterator.
"""
yield path
prefix, ext = os.path.splitext(path)
for i in itertools.count(start=1, step=1):
yield prefix + ' ({0})'.format(i) + ext
def safe_open(path, mode):
"""
Open path, but if it already exists, add " (n)" before the extension,
where n is the first number found such that the file does not already
exist.
Returns an open file handle. Make sure to close!
:param path: Some file name.
:return: Open file handle... be sure to close!
"""
flags = os.O_CREAT | os.O_EXCL | os.O_WRONLY
if 'b' in mode and platform.system() == 'Windows':
flags |= os.O_BINARY
for filename in iter_incrementing_file_names(path):
try:
file_handle = os.open(filename, flags)
except OSError as e:
if e.errno == errno.EEXIST:
pass
else:
raise
else:
return os.fdopen(file_handle, mode)
# Example
with safe_open("some_file.txt", "w") as fh:
print("Hello", file=fh)
I haven't tested this yet but it should work, iterating over possible filenames until the file in question does not exist at which point it breaks.
def increment_filename(fn):
fn, extension = os.path.splitext(path)
n = 1
yield fn + extension
for n in itertools.count(start=1, step=1)
yield '%s%d.%s' % (fn, n, extension)
for filename in increment_filename(original_filename):
if not os.isfile(filename):
break