从 zip 中提取文件而不使用 python zipfile 保留***文件夹
Posted
技术标签:
【中文标题】从 zip 中提取文件而不使用 python zipfile 保留***文件夹【英文标题】:Extract files from zip without keep the top-level folder with python zipfile 【发布时间】:2011-12-31 18:49:44 【问题描述】:我正在使用当前代码从 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
有什么想法吗?
【问题讨论】:
【参考方案1】:如果我正确理解您的问题,您希望在解压缩之前从 zip 中的项目中去除任何常见的前缀目录。
如果是这样,那么下面的脚本应该做你想做的事:
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))
【讨论】:
请您添加一些 cmets 以便更好地了解这里发生了什么? @aturegano。我在示例代码中添加了一些 cmets。 zipinfo 对象的文件名是可写的。因此,该脚本会从存档中的所有文件中去除公共前缀,然后再将它们提取到目标目录。【参考方案2】:读取ZipFile.namelist()
返回的条目,看看它们是否在同一个目录中,然后打开/读取每个条目并将其写入用open()
打开的文件中。
【讨论】:
【参考方案3】:这可能是 zip 存档本身的问题。在 python 提示符下尝试此操作以查看文件是否位于 zip 文件本身的正确目录中。
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' 如果不是这种情况,那么 zip 文件不包含目录,将全部解压缩到一个目录。
【讨论】:
【参考方案4】:根据@ekhumoro 的回答,我想出了一个更简单的函数来提取同一级别的所有内容,这不完全是您的要求,但我认为可以帮助某人。
def _basename_members(self, zip_file: ZipFile):
for zipinfo in zip_file.infolist():
zipinfo.filename = os.path.basename(zipinfo.filename)
yield zipinfo
from_zip="some.zip"
to_folder="some_destination/"
with ZipFile(file=from_zip, mode="r") as zip_file:
os.makedirs(to_folder, exist_ok=True)
zip_infos = self._basename_members(zip_file)
zip_file.extractall(path=to_folder, members=zip_infos)
【讨论】:
以上是关于从 zip 中提取文件而不使用 python zipfile 保留***文件夹的主要内容,如果未能解决你的问题,请参考以下文章
Python zipfile 库 - 从一个目录创建一个仅包含 .pdf 和 .xml 文件的 zip
从 Python3 中的 .zip 文件中提取和读取 [重复]