Как создать файл на python без перезаписи существующего файла
В настоящее время у меня есть цикл, который пытается найти неиспользуемое имя файла, добавляя суффиксы в строку имени файла. Когда он не находит файл, он использует имя, которое не может открыть новый файл с этим именем. Проблема заключается в том, что этот код используется на веб-сайте и может быть несколько попыток сделать одно и то же в одно и то же время, поэтому существует условие гонки.
Как я могу заставить python перезаписывать существующий файл, если он создается между временем проверки и временем открытия в другом потоке.
Я могу свести к минимуму вероятность рандомизации суффиксов, но шанс уже минимизирован на основе частей пути. Я хочу исключить этот шанс с помощью функции, которую можно сказать, создайте этот файл ТОЛЬКО, если он не существует.
Я могу использовать функции win32 для этого, но я хочу, чтобы это работало на кросс-платформе, потому что в конце концов оно будет размещено на linux.
Ответы
Ответ 1
Используйте os.open()
с помощью os.O_CREAT
и os.O_EXCL
, чтобы создать файл. Это произойдет, если файл уже существует:
>>> fd = os.open("x", os.O_WRONLY | os.O_CREAT | os.O_EXCL)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: [Errno 17] File exists: 'x'
Как только вы создали новый файл, используйте os.fdopen()
, чтобы превратить дескриптор в стандартный файл Python:
>>> fd = os.open("y", os.O_WRONLY | os.O_CREAT | os.O_EXCL)
>>> f = os.fdopen(fd, "w") # f is now a standard Python file object
Изменить: Из Python 3.3 встроенный open()
имеет режим x
, который означает "open для исключительного создания, если файл уже существует".
Ответ 2
Если вас беспокоит состояние гонки, вы можете создать временный файл и затем переименовать его.
>>> import os
>>> import tempfile
>>> f = tempfile.NamedTemporaryFile(delete=False)
>>> f.name
'c:\\users\\hughdb~1\\appdata\\local\\temp\\tmpsmdl53'
>>> f.write("Hello world")
>>> f.close()
>>> os.rename(f.name, r'C:\foo.txt')
>>> if os.path.exists(r'C:\foo.txt') :
... print 'File exists'
...
File exists
В качестве альтернативы вы можете создавать файлы с помощью uuid в имени. fooobar.com/questions/5074/....
>>> import uuid
>>> str(uuid.uuid1())
'64362370-93ef-11de-bf06-0023ae0b04b8'
Ответ 3
Если у вас есть id
, связанный с каждым потоком/процессом, который пытается создать файл, вы можете поместить его в суффикс где-то, тем самым гарантируя, что ни один из двух процессов не может использовать одно и то же имя файла.
Это устраняет условие гонки между процессами.