Python3实现zip分卷压缩过程解析


Posted in Python onOctober 09, 2019

使用zipfile库

查看 官方中文文档

利用 Python 压缩 ZIP 文件,我们第一反应是使用 zipfile 库,然而,它的官方文档中却明确标注“此模块目前不能处理分卷 ZIP 文件”,(⊙?⊙)

折腾经过

翻遍了Google、CSDN、Stackoverflow等平台均未找到解决方案,最靠谱的是调用外部解压程序实现分卷压缩的功能。但是,如何不依靠外部程序实现这个功能呢??

于是乎,只能自己慢慢造轮子。看着 ZIP 格式开发商留下的文档 ZIP File Format Specification,头疼啊(;´д`)。于是我拿着 WinHex 开始16进制一个一个文件对比 WinRar 创建的分卷压缩和单个 zip 文件的差异。最后还真的整出来了( ̄? ̄)"

Python3实现zip分卷压缩过程解析

如果想把单个大文件 test.zip -> 分卷文件 test.z01、test.z02、test.zip

首先,在创建的第一个分卷文件 test.z01的前面加上 \x50\x4b\x07\x08 这个是分卷压缩的文件头(header),占4个字节。其实单个压缩文件本身 header 就有这个了,而分卷压缩的需要两个emmm。之后便是从单个大压缩文件文件test.zip中读取 "一个分卷大小 -4 个字节"的数据,写入test.z01中,如何接着读取一个分卷大小的数据,写入test.z02,以此类推,最后一个分卷文件名也是test.zip。

Python3的代码实现

import os
import zipfile


def zip_by_volume(file_path, block_size):
  """zip文件分卷压缩"""
  file_size = os.path.getsize(file_path) # 文件字节数
  path, file_name = os.path.split(file_path) # 除去文件名以外的path,文件名
  suffix = file_name.split('.')[-1] # 文件后缀名
  # 添加到临时压缩文件
  zip_file = file_path + '.zip'
  with zipfile.ZipFile(zip_file, 'w') as zf:
    zf.write(file_path, arcname=file_name)
  # 小于分卷尺寸则直接返回压缩文件路径
  if file_size <= block_size:
    return zip_file
  else:
    fp = open(zip_file, 'rb')
    count = file_size // block_size + 1
    # 创建分卷压缩文件的保存路径
    save_dir = path + os.sep + file_name + '_split'
    if os.path.exists(save_dir):
      from shutil import rmtree
      rmtree(save_dir)
    os.mkdir(save_dir)
    # 拆分压缩包为分卷文件
    for i in range(1, count + 1):
      _suffix = 'z{:0>2}'.format(i) if i != count else 'zip'
      name = save_dir + os.sep + file_name.replace(str(suffix), _suffix)
      f = open(name, 'wb+')
      if i == 1:
        f.write(b'\x50\x4b\x07\x08') # 添加分卷压缩header(4字节)
        f.write(fp.read(block_size - 4))
      else:
        f.write(fp.read(block_size))
    fp.close()
    os.remove(zip_file)   # 删除临时的 zip 文件  
    return save_dir

if __name__ == '__main__':
  file = r"D:\Downloads\1.mp4"    # 原始文件
  volume_size = 1024 * 1024 * 100 # 分卷大小 100MB
  path = zip_by_volume(file, volume_size)
  print(path)   # 输出分卷压缩文件的路径

缺点

该方法创建分卷压缩的时候,需要先在磁盘创建一个临时压缩包,然后将其拆分,实际上会对磁盘写入两次,这就浪费了时间。

当然,我尝试使用 ByteIO 进行字节流的压缩,但是这种方式需要先把文件读入内存,对于超级大的文件,这是不现实的,分分钟内存爆炸。

然后,我尝试使用 io.pipe 的管道来处理,而 zipfile 压缩需要提供一个 file 或 file-like 对象,这个对象必须实现 seek() 和 tell() 方法来回去写入文件头信息,然而管道流没办法seek回去修改数据。这里,参考了Python zipfile + os.pipe()探索记,屏蔽了 seek() 和 tell() 函数。但是,后面我分卷时需要指定读取的字节数,这就需要这两个函数。。。我大概知道为什么 zipfile 库不支持创建分卷文件了???

这个库的作者也没少掉头发。。。现在就将就一下,这样用着吧。。。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python写的英文字符大小写转换代码示例
Mar 06 Python
以Flask为例讲解Python的框架的使用方法
Apr 29 Python
使用Python的Flask框架表单插件Flask-WTF实现Web登录验证
Jul 12 Python
Python常见MongoDB数据库操作实例总结
Jul 24 Python
OpenCV2从摄像头获取帧并写入视频文件的方法
Aug 03 Python
利用Python正则表达式过滤敏感词的方法
Jan 21 Python
Python 用三行代码提取PDF表格数据
Oct 13 Python
Python将列表中的元素转化为数字并排序的示例
Dec 25 Python
python Tensor和Array对比分析
Jan 08 Python
Python接口开发实现步骤详解
Apr 26 Python
Python实现打包成库供别的模块调用
Jul 13 Python
Pandas搭配lambda组合使用详解
Jan 22 Python
基于Python新建用户并产生随机密码过程解析
Oct 08 #Python
Python小程序 控制鼠标循环点击代码实例
Oct 08 #Python
Python3 无重复字符的最长子串的实现
Oct 08 #Python
解决python 读取excel时 日期变成数字并加.0的问题
Oct 08 #Python
python3.7 openpyxl 删除指定一列或者一行的代码
Oct 08 #Python
python实现的按要求生成手机号功能示例
Oct 08 #Python
python集合的创建、添加及删除操作示例
Oct 08 #Python
You might like
学习php笔记 字符串处理
2010/10/19 PHP
PHP实现QQ空间自动回复说说的方法
2015/12/02 PHP
php实现文件预览功能
2017/05/23 PHP
php中文乱码问题的终极解决方案汇总
2017/08/01 PHP
Laravel5.5+ 使用API Resources快速输出自定义JSON方法详解
2020/04/06 PHP
Highslide.js是一款基于js实现的网页中图片展示插件
2020/03/30 Javascript
JavaScript高级程序设计 阅读笔记(二十一) JavaScript中的XML
2012/09/14 Javascript
在页面上用action传递参数到后台出现乱码的解决方法
2013/12/31 Javascript
JQuery 传送中文乱码问题的简单解决办法
2016/05/24 Javascript
基于JavaScript实现拖动滑块效果
2017/02/16 Javascript
Vue中的$set的使用实例代码
2018/10/08 Javascript
vue拖拽排序插件vuedraggable使用方法详解
2020/08/21 Javascript
vue实现手机端省市区区域选择
2019/09/27 Javascript
使用p5.js实现动态GIF图片临摹重现
2019/10/23 Javascript
vue中渲染对象中属性时显示未定义的解决
2020/07/31 Javascript
element-ui和vue表单(对话框)验证提示语(残留)清除操作
2020/09/11 Javascript
vue3.0 上手体验
2020/09/21 Javascript
详解Vue2的diff算法
2021/01/06 Vue.js
[15:58]DOTA2国际邀请赛采访专栏:Tongfu.Sansheng&KingJ,DK.rOtk
2013/08/08 DOTA
让python 3支持mysqldb的解决方法
2017/02/14 Python
python数据类型_元组、字典常用操作方法(介绍)
2017/05/30 Python
python输入错误密码用户锁定实现方法
2017/11/27 Python
Python求两个圆的交点坐标或三个圆的交点坐标方法
2018/11/07 Python
多版本python的pip 升级后, pip2 pip3 与python版本失配解决方法
2019/09/11 Python
Python chardet库识别编码原理解析
2020/02/18 Python
python 实现倒计时功能(gui界面)
2020/11/11 Python
乌克兰电子产品和家用电器购物网站:TOUCH
2019/08/09 全球购物
瑞士首家网上药店折扣店:McDrogerie
2020/12/22 全球购物
成教毕业生自我鉴定
2013/10/23 职场文书
中学劳技课教师的自我评价
2014/02/05 职场文书
上课迟到检讨书
2014/02/19 职场文书
垃圾桶标语
2014/06/24 职场文书
2014年教育实习工作总结
2014/11/22 职场文书
上课迟到检讨书范文
2015/05/06 职场文书
golang 如何用反射reflect操作结构体
2021/04/28 Golang
Mysql中mvcc各场景理解应用
2022/08/05 MySQL