从 zip 文件中解压缩选定的文件
Posted
技术标签:
【中文标题】从 zip 文件中解压缩选定的文件【英文标题】:Unzipping selected files from a zip file 【发布时间】:2021-05-25 13:49:00 【问题描述】:我有一个内部文件夹结构为的 zip 文件:
CODE
`-- CODE
`-- CODE
`-- CODE
|-- 2019
| |-- file1.txt
| `-- file2.txt
|-- 2020
| `-- file3.txt
`-- 2021
|-- file4.txt
`-- file5.txt
我想解压缩文件夹结构中的文件,如下所示:
CODE
|-- 2019
| |-- file1.txt
| `-- file2.txt
|-- 2020
| `-- file3.txt
`-- 2021
|-- file4.txt
`-- file5.txt
我可以对其进行硬编码,但是,因为它是一个重复请求,我是否可以通过编程方式处理它以仅解压缩其中包含文件的文件夹。
我当前的代码是:
def unzipfiles(incoming_path):
for path,subdirs,files in os.walk(incoming_path):
for name in files:
if(name.endswith('.zip')):
with zipfile.ZipFile(os.path.join(incoming_path,name), 'r') as zip_ref:
for file in zip_ref.namelist():
out_path=os.path.join(incoming_path,file)
out_path=out_path.replace('CODE/','')
if(out_path[:-1]!=incoming_path):
zip_ref.extract(file,out_path)
但是,它无法正常工作,并且创建的文件夹比 zip 文件中的文件夹多。
【问题讨论】:
如果我理解正确的话,你想解压一个文件,然后删除其中的任何目录,它只包含另一个目录? 没错。 我可以假设目录名称是重复的,和/或包含数据的第一个文件夹是年号吗?换句话说,文件夹CODE
的命名是否与zipfile名称以及所有其他子目录一致?
是的。我创建了一个对我有用的新功能。我已将代码粘贴到答案中。
【参考方案1】:
此代码对我有用。
def removeEmptyFolders(path, removeRoot=True):
if not os.path.isdir(path):
return
files = os.listdir(path)
if len(files):
for f in files:
fullpath = os.path.join(path, f)
if os.path.isdir(fullpath):
removeEmptyFolders(fullpath)
files = os.listdir(path)
if len(files) == 0 and removeRoot:
os.rmdir(path)
【讨论】:
【参考方案2】:我使用的解决方案是将文件的完整路径映射到一个相对较短的名称。对于解决方案,我将采用 OP 提供的 zip 结构。
import os
import re
import pathlib
import shutil
import zipfile
from pprint import pprint
if __name__ == '__main__':
toplevel = os.path.join('files')
new_structure = dict()
# Let's just extract everything
with zipfile.ZipFile('CODE.zip', 'r') as zip_file:
for zip_info in zip_file.infolist():
path = pathlib.PurePath(zip_info.filename)
# This writes the data from the old file to a new file.
if str(path.parent) in new_structure:
source = zip_file.open(zip_info)
target = open(os.path.join(new_structure[str(path.parent)], path.name), "wb")
with source, target:
shutil.copyfileobj(source, target)
# Create the new folder structure mapping, based on the year name.
# The matches are based on numbers in this example, but can be specified.
if re.match('\d+', path.name):
new_structure[str(path)] = os.path.join(toplevel, path.name)
os.makedirs(new_structure[str(path)], exist_ok=True)
pprint(new_structure)
输出 (pprint
),显示重映射结构:
'CODE\\CODE\\CODE\\CODE\\2019': 'files\\2019',
'CODE\\CODE\\CODE\\CODE\\2020': 'files\\2020',
'CODE\\CODE\\CODE\\CODE\\2021': 'files\\2021'
输出是一个具有以下结构的新文件夹:
files
|-- 2019
| |-- file1.txt
| `-- file2.txt
|-- 2020
| `-- file3.txt
`-- 2021
|-- file4.txt
`-- file5.txt
注意事项
有两点很有趣:
正则表达式模式匹配用于确定文件路径'\d+'
,它只接受数字列表,如果您想更精确,可以使用\d4
精确匹配四位数字。
此方法只假设一个较低的级别,也就是说,多个嵌套文件将无法正确解包。为此,if str(path.parent) in new_structure:
行必须更改以考虑多个父路径。
【讨论】:
以上是关于从 zip 文件中解压缩选定的文件的主要内容,如果未能解决你的问题,请参考以下文章