使用Python解压文件并返回所有创建的目录

4 投票
4 回答
8186 浏览
提问于 2025-04-17 14:45

我想知道怎么用Python把一个.zip文件解压到某个目录output_dir,并且获取解压后所有生成的目录列表。比如说,如果我有:

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

outdir是一个可能已经有其他文件或目录的文件夹。当我把myzip.zip解压到这个文件夹里时,我希望unzip能返回在outdir/里因为解压而生成的所有目录。以下是我目前的代码:

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里创建的目录呢?谢谢。

补充:对我来说,最合理的解决方案是只获取压缩文件中的顶层目录,然后递归地遍历这些目录,这样可以确保我能获取到压缩文件生成的所有文件。这可能吗?因为系统特定的行为使得使用namelist几乎不可靠。

4 个回答

0

等它完成后,再查看目录的内容 - 这里有一个不错的例子

1

ZipFile.namelist 这个方法会返回一个压缩文件里所有项目的名字列表。不过,这些名字会包含完整的文件名和它们的目录路径。(一个压缩文件只能包含文件,而不能直接包含目录,所以目录是通过文件名来隐含表示的。)如果你想知道创建了哪些目录,就需要列出每个文件隐含创建的目录。

下面的 dirs_in_zip() 函数可以做到这一点,它会把所有的目录名收集到一个集合里。

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))
9

你可以使用 namelist() 方法来读取压缩文件的内容。目录的后面会有一个路径分隔符:

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

你可以在提取内容之前或之后进行这个操作。

根据你的操作环境,namelist() 的结果可能只显示压缩文件的顶层路径(比如在 Linux 上的 Python),或者可能显示压缩文件的全部内容(比如在 Windows 上的 IronPython)。

namelist() 会返回压缩文件内容的完整列表,目录会用一个路径分隔符来标记。例如,假设有以下文件结构的压缩文件:

./file1
./dir2
./dir2/dir21
./dir3
./dir3/file3
./dir3/dir31
./dir3/dir31/file31

那么通过 zipfile.ZipFile.namelist() 返回的列表会是:

[ 'file1', 
  'dir2/', 
  'dir2/dir21/', 
  'dir3/', 
  'dir3/file3', 
  'dir3/dir31/', 
  'dir3/dir31/file31' ]

撰写回答