如何在Python中创建文件而不覆盖已有文件
目前我有一个循环,它试图通过给文件名添加后缀来找到一个未被使用的文件名。一旦找不到文件,它就会使用这个失败的名字去创建一个新文件。问题是,这段代码是在一个网站上使用的,可能会有多个请求同时尝试做同样的事情,这就导致了竞争条件。
我该如何防止Python在检查和打开文件之间,如果有其他线程创建了同名文件,导致覆盖已有文件呢?
我可以通过随机化后缀来减少这种情况发生的可能性,但根据路径的一部分,这个可能性已经被降低了。我想要一个函数,它可以告诉我:只有在文件不存在的情况下才创建这个文件。
我可以使用win32的函数来实现这个功能,但我希望这个功能能够跨平台,因为最终会在Linux上托管。
4 个回答
0
如果每个尝试创建文件的线程或进程都有一个独特的id
,你可以把这个id
放在文件名的后面,这样就能确保没有两个进程会使用相同的文件名。
这样做可以避免进程之间的竞争问题。
39
使用 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 文件对象,这样你就可以用 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'