在Python中复制符号链接
我想把一个文件 src
复制到目标 dst
,但是如果 src
是一个符号链接的话,我希望保留这个链接,而不是复制文件的内容。复制完成后,使用 os.readlink
应该能返回相同的结果给 src
和 dst
。
在 shutil
模块里,有几个函数,比如 copyfile
、copy
和 copy2
,但这些函数都会复制文件的 内容,而不会保留链接。虽然 shutil.move
的行为是正确的,但它会删除原来的文件。
在 Python 中,有没有内置的方法可以在复制文件时保留符号链接呢?
2 个回答
只需要这样做
def copy(src, dst):
if os.path.islink(src):
linkto = os.readlink(src)
os.symlink(linkto, dst)
else:
shutil.copy(src,dst)
shutil.copytree 是一个类似的功能,但正如senderle提到的,它只会复制文件夹,而不会单独复制文件。
Python 3 中的 follow_symlinks
在 Python 3 中,shutil
里的大部分复制方法都增加了一个叫 follow_symlinks
的参数,这个参数可以选择保留符号链接。
比如说,对于 shutil.copy
:
shutil.copy(src, dest, follow_symlinks=False)
而且文档中说:
shutil.copy(src, dst, *, follow_symlinks=True)
这个方法会把源文件 src 复制到目标文件或目录 dst。src 和 dst 应该是字符串。如果 dst 指定的是一个目录,那么文件会用 src 的基本文件名复制到 dst 中。返回的是新创建文件的路径。
如果
follow_symlinks
设置为 false,并且 src 是一个符号链接,那么 dst 会被创建为一个符号链接。如果follow_symlinks
设置为 true,并且 src 是一个符号链接,那么 dst 会是 src 指向的文件的副本。
不过,这里有一个问题:如果你尝试覆盖一个已经存在的文件或符号链接,会失败,并显示:
FileExistsError: [Errno 17] File exists: 'b' -> 'c'
而如果 follow_symlinks=True
,就能成功覆盖。
同样的情况也发生在 os.symlink
上,所以我最后选择使用:
#!/usr/bin/env python3
import shutil
import os
def copy(src, dst):
if os.path.islink(src):
if os.path.lexists(dst):
os.unlink(dst)
linkto = os.readlink(src)
os.symlink(linkto, dst)
else:
shutil.copy(src, dst)
if __name__ == '__main__':
os.symlink('c', 'b')
os.symlink('b', 'a')
copy('a', 'b')
with open('c', 'w') as f:
f.write('a')
with open('d', 'w'):
pass
copy('c', 'd')
copy('a', 'c')
在 Ubuntu 18.10 和 Python 3.6.7 中测试过。