Как создать файл в Python без перезаписи существующего файла - PullRequest
20 голосов
/ 28 августа 2009

В настоящее время у меня есть цикл, который пытается найти неиспользуемое имя файла, добавляя суффиксы к строке имени файла. Как только он не может найти файл, он использует имя, которому не удалось открыть новый файл с этим именем. Проблема в том, что этот код используется на веб-сайте, и может быть несколько попыток сделать то же самое одновременно, поэтому существует условие гонки.

Как я могу сохранить python от перезаписи существующего файла, если он создан между временем проверки и временем открытия в другом потоке.

Я могу минимизировать вероятность, рандомизируя суффиксы, но вероятность уже сведена к минимуму на основе частей имени пути. Я хочу исключить этот шанс с помощью функции, которую можно сказать, создавайте этот файл ТОЛЬКО, если он не существует.

Я могу использовать для этого функции win32, но я хочу, чтобы это работало кроссплатформенно, потому что в конце концов оно будет размещено на Linux.

Ответы [ 3 ]

37 голосов
/ 28 августа 2009

Используйте 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, который означает «открыть для эксклюзивного создания, если файл уже существует».

7 голосов
/ 28 августа 2009

Если вас беспокоит состояние гонки, вы можете создать временный файл и затем переименовать его.

>>> 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 в имени. Stackoverflow предмет на этом.

>>> import uuid
>>> str(uuid.uuid1())
'64362370-93ef-11de-bf06-0023ae0b04b8'
0 голосов
/ 28 августа 2009

Если у вас есть id, связанный с каждым потоком / процессом, который пытается создать файл, вы можете поместить этот идентификатор в суффикс где-то, гарантируя, что никакие два процесса не могут использовать одно и то же имя файла.

Это устраняет состояние гонки между процессами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...