在上传数据备份到云端的时候,由于数据文件过大,可能会遇到各种各样的问题:
比如 49G 的大文件 git lfs push 到 99% 突然失败,你说心态爆炸不爆炸?
再比如某些网盘会限制单个文件上传大小限制在 4G 以内;
因此我们可能会用7z之类的压缩软件对数据文件进行分卷压缩,得到多个分卷文件,例如下面的例子:
将歌词文件夹 lyrics 压缩成6个分卷,后缀为 *.zip.00*
的格式。用鼠标操作解压这种多个分卷文件很容易,操作如下图所示:
然而有时候我们需要实现数据下载+解压的自动化,比如将数据集集成到 datasets 之类的 pypi 的 API,就需要对云端下载下来的 zip 分卷文件用代码实现解压。下面我们来提供在 python 下实现 zip 分卷解压的解决方案:
import os
import re
import zipfile
from tqdm import tqdm
def sort_files_by_extension(files):
def key_function(file_path):
# 获取文件路径的后缀名,以数字作为排序键
return int(file_path.split('.')[-1])
# 使用自定义的排序函数进行排序
sorted_files = sorted(files, key=key_function)
return sorted_files
def get_files_with_order(folder_path):
files = []
for file_name in os.listdir(folder_path):
if re.match(r'.+\.zip\.\d{3}$', file_name):
files.append(os.path.join(folder_path, file_name))
return sort_files_by_extension(files)
def merge_files(input_files, output_file):
with open(output_file, 'wb') as merged_file:
for input_file in tqdm(input_files, desc="Merging..."):
with open(input_file, 'rb') as f:
merged_file.write(f.read())
def extract_zip(zip_file, extract_dir):
# 确保目标目录存在
os.makedirs(extract_dir, exist_ok=True)
# 获取ZIP文件中的文件总数
with zipfile.ZipFile(zip_file) as zip_ref:
total_files = len(zip_ref.infolist())
# 使用tqdm显示进度条
with tqdm(total=total_files, desc='Extracting...', unit='file') as pbar:
# 解压每个文件
for file in zip_ref.infolist():
zip_ref.extract(file, extract_dir)
pbar.update(1)
def extract_multi_vol_zip(input_dir='folder_containing_vols', output_dir='outdir'):
tmp_file = 'merged.zip'
input_files = get_files_with_order(input_dir)
merge_files(input_files, tmp_file)
extract_zip(tmp_file, output_dir)
os.remove(tmp_file)
extract_multi_vol_zip()
其中 folder_containing_vols
便是包含所有分卷文件的文件夹,outdir
为导出解压结果的目标路径。其核心原理是:先将分卷文件按照后缀名序号顺序以字节流首尾相连,合并成单个 merge.zip
文件,后面再按照常规的解压单个 .zip
文件的方法提取压缩包。我们分别在合并文件流与解压步骤中添加了进度条,以便直观查看进度。