如何在Python中创建文件而不覆盖已有文件

25 投票
4 回答
12912 浏览
提问于 2025-04-15 13:56

目前我有一个循环,它试图通过给文件名添加后缀来找到一个未被使用的文件名。一旦找不到文件,它就会使用这个失败的名字去创建一个新文件。问题是,这段代码是在一个网站上使用的,可能会有多个请求同时尝试做同样的事情,这就导致了竞争条件。

我该如何防止Python在检查和打开文件之间,如果有其他线程创建了同名文件,导致覆盖已有文件呢?

我可以通过随机化后缀来减少这种情况发生的可能性,但根据路径的一部分,这个可能性已经被降低了。我想要一个函数,它可以告诉我:只有在文件不存在的情况下才创建这个文件。

我可以使用win32的函数来实现这个功能,但我希望这个功能能够跨平台,因为最终会在Linux上托管。

4 个回答

0

如果每个尝试创建文件的线程或进程都有一个独特的id,你可以把这个id放在文件名的后面,这样就能确保没有两个进程会使用相同的文件名。

这样做可以避免进程之间的竞争问题。

39

使用 os.open() 函数,并配合 os.O_CREATos.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 文件对象,这样你就可以用 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

如果你担心出现竞争条件的问题,可以创建一个临时文件,然后再把它重命名。

>>> 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'

撰写回答