不确定为什么会这样,但是当我在命令行运行解压缩文件(例如 apache-groovy-binary-2.4.7.zip)时...
- 目录是
rwx-r-xr-x
- 文件是
rwxr-xr-x
或rw-r--r--
但是当我从同一文件上的 Python 2.7 脚本运行 zipfile.extractall()
时...
- 目录是
rwx-r-x---
- 文件都是
rw-r-----
- 即使是按照上面的规定应该是可执行文件。
我的 umask
设置是 0027
— 这部分解释了发生了什么,但为什么要从所有文件中删除可执行位?
让 Python 采用与命令行版本相似的行为的最简单修复方法是什么(当然,除了 shelling out!)?
最佳答案
原因可以在zipfile.py
中的_extract_member()
方法中找到,它只调用了shutil.copyfileobj()
这将写入没有任何执行位的输出文件。
解决这个问题的最简单方法是继承 ZipFile
并更改 extract()
(或在扩展版本中打补丁。默认情况下是:
def extract(self, member, path=None, pwd=None):
"""Extract a member from the archive to the current working directory,
using its full name. Its file information is extracted as accurately
as possible. `member' may be a filename or a ZipInfo object. You can
specify a different directory using `path'.
"""
if not isinstance(member, ZipInfo):
member = self.getinfo(member)
if path is None:
path = os.getcwd()
return self._extract_member(member, path, pwd)
最后一行应该更改为根据原始属性实际设置模式。你可以这样做:
import os
import sys
from zipfile import ZipFile, ZipInfo
class MyZipFile(ZipFile):
if sys.version_info < (3, 6):
def extract(self, member, path=None, pwd=None):
if not isinstance(member, ZipInfo):
member = self.getinfo(member)
if path is None:
path = os.getcwd()
ret_val = self._extract_member(member, path, pwd)
attr = member.external_attr >> 16
os.chmod(ret_val, attr)
return ret_val
else:
def _extract_member(member, ZipInfo):
if not isinstance(member, ZipInfo):
member = self.getinfo(member)
path = super(ZipFile, self)._extract_member(member, targetpath, pwd)
if member.external_attr > 0xffff:
os.chmod(path, member.external_attr >> 16)
return path
with MyZipFile('test.zip') as zfp:
zfp.extractall()
(以上基于 Python 3.5 并假设压缩文件名为 test.zip
)
关于Python zipfile 从二进制文件中删除执行权限,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39296101/