关于压缩:用python解压文件并返回它创建的所有目录

unzipping a file with Python and returning all the directories it creates

如何用python将.zip文件解压到某个目录output_dir中,并获取解压所生成的所有目录的列表?例如,如果我有:

unzip('myzip.zip', 'outdir')

outdir是一个目录,其中可能包含其他文件/目录。当我将myzip.zip解压缩到其中时,我希望unzip返回所有在outdir/中由于压缩而生成的目录。以下是迄今为止我的代码:

1
2
3
4
5
6
7
import zipfile
def unzip(zip_file, outdir):
   """
    Unzip a given 'zip_file' into the output directory 'outdir'.
   """

    zf = zipfile.ZipFile(zip_file,"r")
    zf.extractall(outdir)

我怎样才能让unzip返回它在outdir中产生的dir?谢谢。

编辑:对我来说最有意义的解决方案是只获取zip文件中的顶级目录,然后递归地遍历这些目录,这将确保我获得zip生成的所有文件。这有可能吗?名称列表的系统特定行为使其几乎不可能依赖


您可以使用namelist()方法读取zip文件的内容。目录将有一个尾随路径分隔符:

1
2
3
4
>>> import zipfile
>>> zip = zipfile.ZipFile('test.zip')
>>> zip.namelist()
['dir2/', 'file1']

您可以在提取内容之前或之后执行此操作。

根据您的操作环境,namelist()的结果可能仅限于zip存档的顶级路径(例如,Linux上的python)或可能覆盖存档的全部内容(例如,Windows上的ironpython)。

namelist()返回一个完整的zip存档内容列表,其中目录用尾随路径分隔符标记。例如,以下文件结构的zip存档:

1
2
3
4
5
6
7
./file1
./dir2
./dir2/dir21
./dir3
./dir3/file3
./dir3/dir31
./dir3/dir31/file31

zipfile.ZipFile.namelist()返回的结果如下:

1
2
3
4
5
6
7
[ 'file1',
  'dir2/',
  'dir2/dir21/',
  'dir3/',
  'dir3/file3',
  'dir3/dir31/',
  'dir3/dir31/file31' ]


ZipFile.namelist将返回存档中项目的名称列表。但是,这些名称将只是文件的全名,包括它们的目录路径。(zip文件只能包含文件,不能包含目录,因此目录是由存档成员名称隐含的。)要确定创建的目录,需要每个文件隐式创建的每个目录的列表。

下面的dirs_in_zip()函数将执行此操作,并将所有dir名称收集到一个集合中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import zipfile
import os

def parent_dirs(pathname, subdirs=None):
   """Return a set of all individual directories contained in a pathname

    For example, if 'a/b/c.ext' is the path to the file 'c.ext':
    a/b/c.ext -> set(['a','a/b'])
   """

    if subdirs is None:
        subdirs = set()
    parent = os.path.dirname(pathname)
    if parent:
        subdirs.add(parent)
        parent_dirs(parent, subdirs)
    return subdirs


def dirs_in_zip(zf):
   """Return a list of directories that would be created by the ZipFile zf"""
    alldirs = set()
    for fn in zf.namelist():
        alldirs.update(parent_dirs(fn))
    return alldirs


zf = zipfile.ZipFile(zipfilename, 'r')

print(dirs_in_zip(zf))


假设没有其他人同时写入目标目录,在解压之前递归地遍历该目录,然后比较结果。


让它完成,然后阅读目录的内容——这里是一个很好的例子。