如果 Python 中不存在,则以原子方式创建文件
Atomically creating a file if it doesn't exist in Python
我正在寻找以下的原子版本:
import os
def tryMakeFile(filename):
try:
with open(filename) as _:
return False
except FileNotFoundError:
with open(filename, mode='a') as _:
return True
(请不要在这里评论文体问题 - 我知道这段代码在很多方面都很糟糕,但足以说明我的问题。)
换句话说,我正在寻找一种方法来检查文件是否存在,如果不存在则创建它,在 Python 中,我知道发生了什么。但是这样做的方式使得多个进程之间没有竞争条件(在我给出的示例代码中,如果第二个进程 运行 而第一个进程在第一次和第二次公开征集)。
或者,换句话说,我正在寻找 Python 相当于 Java 的 Files.createFile 调用。
编辑:请注意,当我说 "Python" 时,我的意思是 "portable Python"。说 "use this library* (*this library is only available on Windows, or not on Windows, or only on the second Tuesday after a blue moon)" 不是我要找的。我正在寻找明确原子性的东西,它是标准库 and/or 内置函数的一部分,并且在通用平台上可用。
如果你有 Python 3.3 或更高版本,你可以使用 'x' 模式 open()
:
'x' open for exclusive creation, failing if the file already exists
def tryMakeFile(filename):
try:
with open(filename, "x") as _:
return False
except FileExistsError:
return True
您可以使用 os.open with os.O_CREAT | os.O_EXCL
flags,如果文件存在,它会失败,它们是根据文档 在 Unix 上可用和 Windows 但我不是确定 windows 上是否存在原子文件创建:
os.open("filename", os.O_CREAT | os.O_EXCL)
来自linux open man page:
O_EXCL
If O_CREAT and O_EXCL are set, open() shall fail if the file exists. The check for the existence of the file and the creation of the file if it does not exist shall be atomic with respect to other threads executing open() naming the same filename in the same directory with O_EXCL and O_CREAT set. If O_EXCL and O_CREAT are set, and path names a symbolic link, open() shall fail and set errno to [EEXIST], regardless of the contents of the symbolic link. If O_EXCL is set and O_CREAT is not set, the result is undefined.
不确定如果文件存在你想做什么但你只需要在文件已经存在时捕获 FileExistsError
:
import os
def try_make_file(filename):
try:
os.open(filename, os.O_CREAT | os.O_EXCL)
return True
except FileExistsError:
return False
还有另一种变体,使用 pathlib.Path
:
from pathlib import Path
def try_make_file(filename):
try:
Path(filename).touch(exist_ok=False)
return True
except FileExistsError:
return False
它没有明确记录,但在源代码中我们可以看到这暗示了 os.O_EXCL
标志:
if not exist_ok:
flags |= os.O_EXCL
见the function definition in the pathlib source code。
因此,这与其他解决方案具有相同的属性(即尚不清楚这是否适用于 Windows)。
我正在寻找以下的原子版本:
import os
def tryMakeFile(filename):
try:
with open(filename) as _:
return False
except FileNotFoundError:
with open(filename, mode='a') as _:
return True
(请不要在这里评论文体问题 - 我知道这段代码在很多方面都很糟糕,但足以说明我的问题。)
换句话说,我正在寻找一种方法来检查文件是否存在,如果不存在则创建它,在 Python 中,我知道发生了什么。但是这样做的方式使得多个进程之间没有竞争条件(在我给出的示例代码中,如果第二个进程 运行 而第一个进程在第一次和第二次公开征集)。
或者,换句话说,我正在寻找 Python 相当于 Java 的 Files.createFile 调用。
编辑:请注意,当我说 "Python" 时,我的意思是 "portable Python"。说 "use this library* (*this library is only available on Windows, or not on Windows, or only on the second Tuesday after a blue moon)" 不是我要找的。我正在寻找明确原子性的东西,它是标准库 and/or 内置函数的一部分,并且在通用平台上可用。
如果你有 Python 3.3 或更高版本,你可以使用 'x' 模式 open()
:
'x' open for exclusive creation, failing if the file already exists
def tryMakeFile(filename):
try:
with open(filename, "x") as _:
return False
except FileExistsError:
return True
您可以使用 os.open with os.O_CREAT | os.O_EXCL
flags,如果文件存在,它会失败,它们是根据文档 在 Unix 上可用和 Windows 但我不是确定 windows 上是否存在原子文件创建:
os.open("filename", os.O_CREAT | os.O_EXCL)
来自linux open man page:
O_EXCL If O_CREAT and O_EXCL are set, open() shall fail if the file exists. The check for the existence of the file and the creation of the file if it does not exist shall be atomic with respect to other threads executing open() naming the same filename in the same directory with O_EXCL and O_CREAT set. If O_EXCL and O_CREAT are set, and path names a symbolic link, open() shall fail and set errno to [EEXIST], regardless of the contents of the symbolic link. If O_EXCL is set and O_CREAT is not set, the result is undefined.
不确定如果文件存在你想做什么但你只需要在文件已经存在时捕获 FileExistsError
:
import os
def try_make_file(filename):
try:
os.open(filename, os.O_CREAT | os.O_EXCL)
return True
except FileExistsError:
return False
还有另一种变体,使用 pathlib.Path
:
from pathlib import Path
def try_make_file(filename):
try:
Path(filename).touch(exist_ok=False)
return True
except FileExistsError:
return False
它没有明确记录,但在源代码中我们可以看到这暗示了 os.O_EXCL
标志:
if not exist_ok:
flags |= os.O_EXCL
见the function definition in the pathlib source code。
因此,这与其他解决方案具有相同的属性(即尚不清楚这是否适用于 Windows)。