Un problema es que hay una condición de carrera en el código anterior, ya que hay una brecha entre la prueba de existencia y la creación del archivo. Puede haber implicaciones de seguridad para esto (piense en alguien que inserta maliciosamente un enlace simbólico a un archivo confidencial que no podría sobrescribir, pero su programa que se ejecuta con un privilegio mayor podría) Ataques como estos son el por qué cosas como os.tempnam () están en desuso.
Para evitarlo, el mejor enfoque es tratar de crear el archivo de tal manera que obtendrá una excepción si falla y, en caso de éxito, devolverá el objeto del archivo realmente abierto. Esto se puede hacer con las funciones os.open de nivel inferior, pasando las banderas os.O_CREAT y os.O_EXCL. Una vez abierto, devuelve el archivo real (y, opcionalmente, el nombre de archivo) que crees. Por ejemplo, aquí está el código modificado para utilizar este enfoque (volviendo una presentación (archivo, nombre de archivo) tupla):
def unique_file(file_name):
counter = 1
file_name_parts = os.path.splitext(file_name) # returns ('/path/file', '.ext')
while 1:
try:
fd = os.open(file_name, os.O_CREAT | os.O_EXCL | os.O_RDRW)
return os.fdopen(fd), file_name
except OSError:
pass
file_name = file_name_parts[0] + '_' + str(counter) + file_name_parts[1]
counter += 1
[Editar] En realidad, una mejor manera, que se encargará de las cuestiones antes mencionadas para usted, es probablemente para usar el módulo de tempfile, aunque puede perder cierto control sobre la nomenclatura.He aquí un ejemplo de su uso (manteniendo una interfaz similar):
def unique_file(file_name):
dirname, filename = os.path.split(file_name)
prefix, suffix = os.path.splitext(filename)
fd, filename = tempfile.mkstemp(suffix, prefix+"_", dirname)
return os.fdopen(fd), filename
>>> f, filename=unique_file('/home/some_dir/foo.txt')
>>> print filename
/home/some_dir/foo_z8f_2Z.txt
El único inconveniente de este enfoque es que siempre se obtendrá un nombre de archivo con algunos caracteres aleatorios en el mismo, ya que no hay intento de crear un archivo sin modificar (/home/some_dir/foo.txt) primero. Es posible que también desee examinar tempfile.TemporaryFile y NamedTemporaryFile, que hará lo anterior y también eliminará automáticamente del disco cuando se cierre.
Sí, este es The_Right_Way para hacerlo. ¡Ojalá pudiera moderarme y poner tu respuesta en la cima! –
Pequeño error tipográfico: debería ser 'os.O_RDWR' en lugar de' os.O_RDRW' – tremby