使用Python zipfile提取zip文件时不保留顶层文件夹

8 投票
5 回答
8643 浏览
提问于 2025-04-17 09:20

我正在使用当前的代码从一个zip文件中提取文件,同时保持目录结构:

zip_file = zipfile.ZipFile('archive.zip', 'r')
zip_file.extractall('/dir/to/extract/files/')
zip_file.close()

这是一个示例zip文件的结构:

/dir1/file.jpg
/dir1/file1.jpg
/dir1/file2.jpg

最后我想要这样的结果:

/dir/to/extract/file.jpg
/dir/to/extract/file1.jpg
/dir/to/extract/file2.jpg

但是只有当zip文件的最上层有一个文件夹,里面包含所有文件时,它才应该忽略这个文件夹。所以当我提取一个具有以下结构的zip文件时:

/dir1/file.jpg
/dir1/file1.jpg
/dir1/file2.jpg
/dir2/file.txt
/file.mp3

它应该保持这样的样子:

/dir/to/extract/dir1/file.jpg
/dir/to/extract/dir1/file1.jpg
/dir/to/extract/dir1/file2.jpg
/dir/to/extract/dir2/file.txt
/dir/to/extract/file.mp3

有什么想法吗?

5 个回答

1

查看通过 ZipFile.namelist() 返回的文件列表,看看它们是否在同一个文件夹里。然后,逐个打开和读取这些文件,并把它们写入用 open() 打开的文件中。

1

这可能是压缩文件本身的问题。在Python的命令行中,你可以试试下面的方法,看看压缩文件里的文件是否在正确的目录下。

import zipfile

zf = zipfile.ZipFile("my_file.zip",'r')
first_file = zf.filelist[0]
print file_list.filename

这应该会显示类似“dir1”的内容。接着,重复上面的步骤,把文件列表中的索引改成1,像这样 first_file = zf.filelist[1]。这次的输出应该是' dir1/file1.jpg',如果不是这样,那说明这个压缩文件里没有目录,解压后所有文件都会放在同一个目录里。

7

如果我理解你的问题没错的话,你是想在解压缩之前,把压缩包里所有文件的共同前缀目录去掉。

如果是这样的话,下面这个脚本应该可以满足你的需求:

import sys, os
from zipfile import ZipFile

def get_members(zip):
    parts = []
    # get all the path prefixes
    for name in zip.namelist():
        # only check files (not directories)
        if not name.endswith('/'):
            # keep list of path elements (minus filename)
            parts.append(name.split('/')[:-1])
    # now find the common path prefix (if any)
    prefix = os.path.commonprefix(parts)
    if prefix:
        # re-join the path elements
        prefix = '/'.join(prefix) + '/'
    # get the length of the common prefix
    offset = len(prefix)
    # now re-set the filenames
    for zipinfo in zip.infolist():
        name = zipinfo.filename
        # only check files (not directories)
        if len(name) > offset:
            # remove the common prefix
            zipinfo.filename = name[offset:]
            yield zipinfo

args = sys.argv[1:]

if len(args):
    zip = ZipFile(args[0])
    path = args[1] if len(args) > 1 else '.'
    zip.extractall(path, get_members(zip))

撰写回答