【问题标题】:How do I set permissions (attributes) on a file in a ZIP file using Python's zipfile module?如何使用 Python 的 zipfile 模块对 ZIP 文件中的文件设置权限(属性)?
【发布时间】:2010-09-30 21:11:17
【问题描述】:

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

文件正在 Linux 和 Python 2.5.2 下创建和提取。

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

【问题讨论】:

    标签: python attributes zip file-permissions zipfile


    【解决方案1】:

    看看这个:Set permissions on a compressed file in python

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

    关键线似乎是:

    zi.external_attr = 0777 << 16L
    

    看起来它在那里将权限设置为0777

    【讨论】:

      【解决方案2】:

      这似乎行得通(感谢 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

      【讨论】:

      • 如果示例中定义了缓冲区、名称和字节,这将更具可读性。
      • 当然,添加了一些示例定义。
      • 对于python 3,你会写这个0o777 &lt;&lt; 16
      • 另外:正如所写的那样,这段代码会将归档中正在写入的文件标记为最后一次修改于 1980 年; ZipInfo 构造函数将上次修改日期作为另一个构造函数。
      • 查看更新的答案以获得更正确的解决方案stackoverflow.com/a/48435482/305975
      【解决方案3】:

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

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

      如果没有,我建议在 for 循环中添加一个 os.chmod,具有 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)
      

      【讨论】:

      • 我没有使用 Python 来提取 zip,该 zip 是由网络服务器生成并使用用户机器上的某些东西提取的。在我的例子中是 gnome 存档管理程序。
      【解决方案4】:

      This link 拥有的信息比我在网上找到的任何其他信息都多。即使是 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, '')
      

      另外,this link 有以下内容。 这里的低位字节大概是指四个字节中最右边(最低)的字节。所以这个是 对于 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's archives下载的InfoZIP的zip程序源中的源文件unix/unix.c在cmets中有以下内容。

        /* 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 来说是这样。

      编辑:我在问题“The zip format's external file attribute”中询问了 Unix.SX 上这方面的 Unix 方面。看起来我有几件事错了。特别是前两个字节都用于 Unix。

      【讨论】:

      • 如果使用来自 stat 模块的常量(例如 stat.S_IFLNK),示例中的一些常量会更清晰。在查看此内容时,我还发现了unix.stackexchange.com/questions/14705/…
      • @Epu 从技术上讲,不能保证 S_IFLNK 等于 0120000 - 正如我所提到的,“Unix 值与传统的 unix 实现相同”并提供了一个示例,但确切POSIX 不保证数值(S_IFLNK 实际上也不保证作为常量存在),但 0120000 始终表示 zip 上下文中的符号链接,因为它是一种跨平台格式。
      【解决方案5】:

      早期的答案对我不起作用(在 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

      【讨论】:

        【解决方案6】:

        同时看看Python's zipfile module做了什么:

        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
            ...
        

        ```

        【讨论】:

          【解决方案7】:

          您可以扩展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

          相关代码:

          【讨论】:

            【解决方案8】:

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

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

            您也可以导入 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')
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-02-10
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2015-04-05
              相关资源
              最近更新 更多