45

当我从使用 Python 模块创建的 ZIP 文件中提取文件时zipfile,所有文件都不可写、只读等。

该文件是在 Linux 和 Python 2.5.2 下创建和提取的。

据我所知,我需要ZipInfo.external_attr为每个文件设置属性,但这似乎没有记录在我能找到的任何地方,谁能启发我?

4

8 回答 8

48

这似乎可行(感谢 Evan,将其放在这里,以便该行符合上下文):

buffer = "path/filename.zip"  # zip filename to write (or file-like object)
name = "folder/data.txt"      # name of file inside zip 
bytes = "blah blah blah"      # contents of file inside zip

zip = zipfile.ZipFile(buffer, "w", zipfile.ZIP_DEFLATED)
info = zipfile.ZipInfo(name)
info.external_attr = 0777 << 16L # give full access to included file
zip.writestr(info, bytes)
zip.close()

我仍然希望看到记录此内容的内容...我发现的另一个资源是有关 Zip 文件格式的注释:http ://www.pkware.com/documents/casestudies/APPNOTE.TXT

于 2009-01-12T07:14:46.667 回答
26

这个链接比我在网上找到的任何其他信息都多。即使是 zip 源也没有任何内容。为后代复制相关部分。这个补丁并不是真的要记录这种格式,它只是为了显示当前文档是多么可悲(阅读不存在)。

# external_attr is 4 bytes in size. The high order two
# bytes represent UNIX permission and file type bits,
# while the low order two contain MS-DOS FAT file
# attributes, most notably bit 4 marking directories.
if node.isfile:
    zipinfo.compress_type = ZIP_DEFLATED
    zipinfo.external_attr = 0644 << 16L # permissions -r-wr--r--
    data = node.get_content().read()
    properties = node.get_properties()
    if 'svn:special' in properties and \
           data.startswith('link '):
        data = data[5:]
        zipinfo.external_attr |= 0120000 << 16L # symlink file type
        zipinfo.compress_type = ZIP_STORED
    if 'svn:executable' in properties:
        zipinfo.external_attr |= 0755 << 16L # -rwxr-xr-x
    zipfile.writestr(zipinfo, data)
elif node.isdir and path:
    if not zipinfo.filename.endswith('/'):
        zipinfo.filename += '/'
    zipinfo.compress_type = ZIP_STORED
    zipinfo.external_attr = 040755 << 16L # permissions drwxr-xr-x
    zipinfo.external_attr |= 0x10 # MS-DOS directory flag
    zipfile.writestr(zipinfo, '')

此外,此链接具有以下内容。这里的低位字节大概是指四个字节中最右边(最低)的字节。所以这个是用于 MS-DOS 的,否则可能会保留为零。

外部文件属性:(4字节)

      The mapping of the external attributes is
      host-system dependent (see 'version made by').  For
      MS-DOS, the low order byte is the MS-DOS directory
      attribute byte.  If input came from standard input, this
      field is set to zero.

此外,从Debian 档案库下载的 InfoZIP zip 程序的源代码中的源文件 unix/unix.c 在注释中包含以下内容。

  /* lower-middle external-attribute byte (unused until now):
   *   high bit        => (have GMT mod/acc times) >>> NO LONGER USED! <<<
   *   second-high bit => have Unix UID/GID info
   * NOTE: The high bit was NEVER used in any official Info-ZIP release,
   *       but its future use should be avoided (if possible), since it
   *       was used as "GMT mod/acc times local extra field" flags in Zip beta
   *       versions 2.0j up to 2.0v, for about 1.5 years.
   */

所以把所有这些放在一起,看起来实际上只使用了第二高的字节,至少对于 Unix 来说是这样。

编辑:我在“压缩格式的外部文件属性”问题中询问了 Unix.SX 上的 Unix 方面。看起来我有几件事错了。具体来说,前两个字节都用于 Unix。

于 2011-06-09T19:00:35.897 回答
15

看这个:Set permissions on acompressed file in python

我不完全确定这是否是您想要的,但似乎是。

关键线似乎是:

zi.external_attr = 0777 << 16L

看起来它在0777那里设置了权限。

于 2009-01-12T06:57:36.390 回答
9

较早的答案对我不起作用(在 OS X 10.12 上)。我发现除了可执行标志(八进制 755)之外,我还需要设置“常规文件”标志(八进制 100000)。我发现这里提到了这个:https ://unix.stackexchange.com/questions/14705/the-zip-formats-external-file-attribute

一个完整的例子:

zipname = "test.zip"
filename = "test-executable"

zip = zipfile.ZipFile(zipname, 'w', zipfile.ZIP_DEFLATED)

f = open(filename, 'r')
bytes = f.read()
f.close()

info = zipfile.ZipInfo(filename)
info.date_time = time.localtime()
info.external_attr = 0100755 << 16L

zip.writestr(info, bytes, zipfile.ZIP_DEFLATED)

zip.close()

我的特定用例的完整示例,创建 .app 的 zip 以便文件夹中的所有内容Contents/MacOS/都是可执行的:https ://gist.github.com/Draknek/3ce889860cea4f59838386a79cc11a85

于 2018-01-25T04:03:35.403 回答
5

您可以扩展ZipFile类以更改默认文件权限:

from zipfile import ZipFile, ZipInfo
import time

class PermissiveZipFile(ZipFile):
    def writestr(self, zinfo_or_arcname, data, compress_type=None):
        if not isinstance(zinfo_or_arcname, ZipInfo):
            zinfo = ZipInfo(filename=zinfo_or_arcname,
                            date_time=time.localtime(time.time())[:6])

            zinfo.compress_type = self.compression
            if zinfo.filename[-1] == '/':
                zinfo.external_attr = 0o40775 << 16   # drwxrwxr-x
                zinfo.external_attr |= 0x10           # MS-DOS directory flag
            else:
                zinfo.external_attr = 0o664 << 16     # ?rw-rw-r--
        else:
            zinfo = zinfo_or_arcname

        super(PermissiveZipFile, self).writestr(zinfo, data, compress_type)

此示例将默认文件权限更改为664并保留775为目录。

相关代码:

于 2018-12-12T11:37:47.620 回答
1

还要看看Python 的 zipfile 模块做了什么:

def write(self, filename, arcname=None, compress_type=None):
    ...
    st = os.stat(filename)
    ...
    zinfo = ZipInfo(arcname, date_time)
    zinfo.external_attr = (st[0] & 0xFFFF) << 16L      # Unix attributes
    ...

```

于 2018-10-26T11:52:31.057 回答
1

要使用 Python 的 zipfile 模块对 ZIP 文件中的文件设置权限(Unix 属性),请将属性作为 ZipInfo 的 external_attr 的第 16-31 位传递。

Python zipfile 模块在 external_attr 位中接受 Unix 的 ASi 额外块的 16 位“模式”字段(存储来自 struct stat 的 st_mode 字段,包含用户/组/其他权限、setuid/setgid 和符号链接信息等)上面提到的。

您还可以导入 Python 的“stat”模块来获取模式常量定义。

您也可以在 create_system 中设置 3 来指定创建 ZIP 存档的操作系统:3 = Unix;0 = 窗户。

这是一个例子:

#!/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 
    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 
    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')
于 2021-01-21T19:28:57.253 回答
0

当你这样做时,它工作正常吗?

zf = zipfile.ZipFile("something.zip")
for name in zf.namelist():
    f = open(name, 'wb')
    f.write(self.read(name))
    f.close()

如果没有,我建议在os.chmodfor 循环中添加一个 0777 权限,如下所示:

zf = zipfile.ZipFile("something.zip")
for name in zf.namelist():
    f = open(name, 'wb')
    f.write(self.read(name))
    f.close()
    os.chmod(name, 0777)
于 2009-01-12T07:15:11.940 回答