使用Python zipfile归档符号链接

11

我有一个脚本用于创建包含符号链接的目录的zip文件。我惊讶地发现,这些zip文件压缩了链接的目标,而不是链接本身,这不是我想要或期望的结果。有人知道如何让zipfile压缩这些链接吗?

5个回答

10

可以将符号链接存储在zipfile中,而不是文件本身。例如,请参见此处。脚本的相关部分是在zipinfo中存储符号链接属性:

zipInfo = zipfile.ZipInfo(archiveRoot)
zipInfo.create_system = 3
# long type of hex val of '0xA1ED0000L',
# say, symlink attr magic...
zipInfo.external_attr = 2716663808L
zipOut.writestr(zipInfo, os.readlink(fullPath))

3
Python3不区分长整型和整型,因此zipInfo.external_attr = 0xA1ED0000L应该可以工作(这样稍微更易读一些?) - Mark Harviston
2
我看到了更好的实现方式:zipInfo.external_attr |= 0xA0000000 - MarSoft
魔术常量也都可用,例如 stat.S_IFLINK - OrangeDog

7

谢谢。最终我使用了子进程来调用命令行zip并加上--symlinks参数。虽然比Python的zipfile库慢,但它支持符号链接。 - Larry Martell
@LarryMartell Info-ZIP有一个共享库和一个独立的可执行文件,可能可以为您节省一些周期。但我找不到任何文档。 - ivan_pozdeev

4
请查看以下Python代码,作为创建cpuinfo.zip存档文件的完整示例,其中包括一个符号链接cpuinfo.txt,它指向/proc/cpuinfo
#!/usr/bin/python

import stat
import zipfile

def create_zip_with_symlink(output_zip_filename, link_source, link_target):
    zipInfo  = zipfile.ZipInfo(link_source)
    zipInfo.create_system = 3 # System which created ZIP archive, 3 = Unix; 0 = Windows
    unix_st_mode = stat.S_IFLNK | stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IWOTH | stat.S_IXOTH
    zipInfo.external_attr = unix_st_mode << 16 # The Python zipfile module accepts the 16-bit "Mode" field (that stores st_mode field from struct stat, containing user/group/other permissions, setuid/setgid and symlink info, etc) of the ASi extra block for Unix as bits 16-31 of the external_attr
    zipOut = zipfile.ZipFile(output_zip_filename, 'w', compression=zipfile.ZIP_DEFLATED)
    zipOut.writestr(zipInfo, link_target)
    zipOut.close()

create_zip_with_symlink('cpuinfo.zip', 'cpuinfo.txt', '/proc/cpuinfo')

您可以进一步输入以下命令(例如在Ubuntu下),以查看存档如何解压缩为工作符号链接:
unzip cpuinfo.zip
ls -l cpuinfo.txt
cat cpuinfo.txt

1
我已经在Zip支持类中定义了以下方法。
def add_symlink(self, link, target, permissions=0o777):
    self.log('Adding a symlink: {} => {}'.format(link, target))
    permissions |= 0xA000

    zi = zipfile.ZipInfo(link)
    zi.create_system = 3
    zi.external_attr = permissions << 16
    self.zip.writestr(zi, target)

0
虽然不是POSIX标准的一部分,但许多zip实现支持在条目上存储通用文件系统属性。 4字节值的高字节表示文件模式。
基本上,您需要复制ZipInfo.from_file,但是不要跟随链接或截断模式:
st = os.lstat(path)
mtime = time.localtime(st.st_mtime)
info = zipfile.ZipInfo(name, mtime[0:6])
info.file_size = st.st_size
info.external_attr = st.st_mode << 16
out_zip.writestr(info, os.readlink(path))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接