我有一个zip文件,其中包含以下目录结构:
dir1\dir2\dir3a
dir1\dir2\dir3b
我正在尝试解压缩并维护目录结构,但是我收到错误:
IOError: [Errno 2] No such file or directory: 'C:\\\projects\\\testFolder\\\subdir\\\unzip.exe'
其中testFolder是dir1,而subdir是dir2。
是否有快速解压缩文件和维护目录结构的方法?
答案 0 :(得分:23)
如果你使用的是Python 2.6,那么extract和extractall方法都很棒。我现在必须使用Python 2.5,所以我只需要创建目录,如果它们不存在。您可以使用namelist()
方法获取目录列表。目录将始终以正斜杠结束(即使在Windows上),例如,
import os, zipfile
z = zipfile.ZipFile('myfile.zip')
for f in z.namelist():
if f.endswith('/'):
os.makedirs(f)
您可能不希望完全这样做(也就是说,您可能想要在遍历名单时提取zip文件的内容),但是你得到了想法。
答案 1 :(得分:16)
不要信任extract()或extractall()。
这些方法盲目地将文件提取到文件名中给出的路径。但ZIP文件名可以是任何东西,包括危险的字符串,如“x /../../../ etc / passwd”。提取此类文件,您可能只是破坏了整个服务器。
也许这应该被认为是Python的zipfile模块中的一个可报告的安全漏洞,但是过去任何数量的zip-dearchivers都表现出完全相同的行为。要安全地取消归档具有文件夹结构的ZIP文件,您需要深入检查每个文件路径。
答案 2 :(得分:8)
我试过了,可以重现它。如其他答案所示,extractall方法不解决问题。这看起来像zipfile模块中的一个错误(也许仅限于Windows?),除非我误解了zipfiles的结构。
testa\
testa\testb\
testa\testb\test.log
> test.zip
>>> from zipfile import ZipFile
>>> zipTest = ZipFile("C:\\...\\test.zip")
>>> zipTest.extractall("C:\\...\\")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "...\zipfile.py", line 940, in extractall
File "...\zipfile.py", line 928, in extract
File "...\zipfile.py", line 965, in _extract_member
IOError: [Errno 2] No such file or directory: 'C:\\...\\testa\\testb\\test.log'
如果我做printdir()
,我会得到这个(第一栏):
>>> zipTest.printdir()
File Name
testa/testb/
testa/testb/test.log
如果我尝试仅提取第一个条目,请执行以下操作:
>>> zipTest.extract("testa/testb/")
'C:\\...\\testa\\testb'
在磁盘上,这会导致创建一个文件夹testa
,其中包含文件 testb
。这显然是后续尝试提取test.log
失败的原因; testa\testb
是一个文件,而不是文件夹。
编辑#1:如果你只提取文件,那么它可以工作:
>>> zipTest.extract("testa/testb/test.log")
'C:\\...\\testa\\testb\\test.log'
编辑#2:杰夫的代码是要走的路;遍历namelist
;如果是目录,请创建目录。否则,解压缩文件。
答案 3 :(得分:6)
我知道说这可能有点迟,但杰夫是对的。 它很简单:
import os
from zipfile import ZipFile as zip
def extractAll(zipName):
z = zip(zipName)
for f in z.namelist():
if f.endswith('/'):
os.makedirs(f)
else:
z.extract(f)
if __name__ == '__main__':
zipList = ['one.zip', 'two.zip', 'three.zip']
for zip in zipList:
extractAll(zipName)
答案 4 :(得分:3)
如果您使用的是Python 2.6,那么这是一种非常简单的方法:extractall方法。
但是,由于zipfile
模块完全在Python中实现而没有任何C扩展,因此您可以将其从2.6安装中复制出来并将其与旧版本的Python一起使用;您可能会发现这比自己重新实现功能更容易。但是,功能本身很短:
def extractall(self, path=None, members=None, pwd=None):
"""Extract all members from the archive to the current working
directory. `path' specifies a different directory to extract to.
`members' is optional and must be a subset of the list returned
by namelist().
"""
if members is None:
members = self.namelist()
for zipinfo in members:
self.extract(zipinfo, path, pwd)
答案 5 :(得分:2)
听起来你正试图解压缩来解压缩。
最好使用python zipfile
模块,因此在python中进行提取。
import zipfile
def extract(zipfilepath, extractiondir):
zip = zipfile.ZipFile(zipfilepath)
zip.extractall(path=extractiondir)
答案 6 :(得分:2)
您只需过滤掉以namelist()
结尾的/
条目,问题就解决了:
z.extractall(dest, filter(lambda f: not f.endswith('/'), z.namelist()))
的nJoy!
答案 7 :(得分:2)
如果像我一样,你必须提取一个完整的zip存档与旧的Python版本(在我的情况下,2.4)这里是我想出的(基于杰夫的答案):
import zipfile
import os
def unzip(source_file_path, destination_dir):
destination_dir += '/'
z = zipfile.ZipFile(source_file_path, 'r')
for file in z.namelist():
outfile_path = destination_dir + file
if file.endswith('/'):
os.makedirs(outfile_path)
else:
outfile = open(outfile_path, 'wb')
outfile.write(z.read(file))
outfile.close()
z.close()
答案 8 :(得分:1)
请注意,zip文件可以包含目录和文件的条目。使用zip
命令创建存档时,请传递-D
选项以禁用向存档明确添加目录条目。当Python 2.6的ZipFile.extractall
方法在目录条目中运行时,它似乎在其位置创建了文件。由于归档条目不一定按顺序排列,这会导致ZipFile.extractall
经常失败,因为它试图在文件的子目录中创建文件。如果您有要与Python模块一起使用的存档,只需将其解压缩并使用-D
选项重新压缩它。这是我用了一段时间才做到这一点的小片段:
P=`pwd` &&
Z=`mktemp -d -t zip` &&
pushd $Z &&
unzip $P/<busted>.zip &&
zip -r -D $P/<new>.zip . &&
popd &&
rm -rf $Z
将<busted>.zip
和<new>.zip
替换为相对于当前目录的真实文件名。然后只需复制整个内容并将其粘贴到命令shell中,它将创建一个新的存档,可以随时使用Python 2.6。 是一个zip
命令,它将删除这些目录条目而不解压缩,但是IIRC在不同的shell环境或zip配置中表现得很奇怪。