我想要创建一个符号链接,如果需要的话,覆盖现有的文件或符号链接。
我发现os.path.exists
只对非断开的符号链接返回True
,因此我猜测任何测试都必须包括os.path.lexists
。
在Python中实现ln -sf
最原子的方法是什么?(即,在删除和符号链接创建之间防止另一个进程创建文件)
区别:这个问题没有指定原子要求
我想要创建一个符号链接,如果需要的话,覆盖现有的文件或符号链接。
我发现os.path.exists
只对非断开的符号链接返回True
,因此我猜测任何测试都必须包括os.path.lexists
。
在Python中实现ln -sf
最原子的方法是什么?(即,在删除和符号链接创建之间防止另一个进程创建文件)
区别:这个问题没有指定原子要求
import os
import tempfile
def symlink_force(target, link_name):
'''
Create a symbolic link link_name pointing to target.
Overwrites link_name if it exists.
'''
# os.replace() may fail if files are on different filesystems
link_dir = os.path.dirname(link_name)
while True:
temp_link_name = tempfile.mktemp(dir=link_dir)
try:
os.symlink(target, temp_link_name)
break
except FileExistsError:
pass
try:
os.replace(temp_link_name, link_name)
except OSError: # e.g. permission denied
os.remove(temp_link_name)
raise
如果函数中断(例如计算机崩溃),目标可能存在一个额外的随机链接。
仍然存在一个不太可能的竞争条件:在随机命名的 temp_link_name
处创建的符号链接可能在替换 link_name
之前被另一个进程修改。
我提出了一个Python问题,以突出 os.symlink()
需要目标不存在的问题。
mktemp
和 symlink
调用放在一个循环内,重试直到赢得比赛来处理(不太可能的)竞争情况。显然,您需要检查 symlink
失败是因为 EEXIST
而不是其他永远无法成功的原因。为了提高效率,您可能希望将嵌入的 dirname
调用提升到循环之上。 - ottomeistermktemp
命名的文件呢? - Tom Halemktemp
意外地在同一个名称上发生冲突,那么你可以 mkdtemp
一个目录,在该目录中创建新的符号链接,然后将符号链接重命名为原始符号链接(然后 rmdir
临时目录)。文件系统内的 rename
是原子操作。 - ottomeister
ln -s file tmplink
,那么mv tmplink link
是原子操作。 - Amadan