Skip to content

Instantly share code, notes, and snippets.

@alexwlchan
Created February 28, 2017 09:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alexwlchan/e6b35ef3e5cb658d8047deadee6cf629 to your computer and use it in GitHub Desktop.
Save alexwlchan/e6b35ef3e5cb658d8047deadee6cf629 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""Generate unique filenames for a file you're about to create.
The functions in this snippet are useful for ensuring you don't inadvertently
create a file that replaces an existing file. Given a name, they try to
find a similar name that doesn't already exist on the disk.
This code isn't safe from race conditions -- if a file pops into existence
between the check and the write, you could still lose data -- but it's a
good start. If you really want to be sure a file doesn't exist when you
write to it, use the 'x' mode for `open()` in Python 3:
https://alexwlchan.net/2016/03/exclusive-create-python/
"""
import os
import random
import string
def generate_variations(path):
"""Given a path, generate variations that add a few characters of random
noise to the path.
:param path: Starting path.
"""
# Implementation note: the 'noise' is five characters of alphanumeric
# text added before the file extension. Including uppercase and lowercase,
# this allows up to 62^5 = 9e9 possible variations. That's plenty for
# most use cases. Add more characters if you're feeling picky.
yield path
base, ext = os.splitext(path)
while True:
noise = ''.join([
random.choice(string.ascii_letters + string.digits)
for _ in range(5)
])
yield '%s_%s%s' % (base, noise, ext)
def choose_unique_filename(path):
"""Given a filename, return a variation on that filename that doesn't
already exist on disk."""
for new_path in generate_variations(path):
if not os.path.exists(new_path):
return new_path
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment