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 30 Python
为Python程序添加图形化界面的教程
Apr 29 Python
使用相同的Apache实例来运行Django和Media文件
Jul 22 Python
详解使用 pyenv 管理多个版本 python 环境
Oct 19 Python
python实现发送邮件功能代码
Dec 14 Python
详谈python中冒号与逗号的区别
Apr 18 Python
python绘制直方图和密度图的实例
Jul 08 Python
python 进程 进程池 进程间通信实现解析
Aug 23 Python
Node.js 和 Python之间该选择哪个?
Aug 05 Python
详解如何在pyqt中通过OpenCV实现对窗口的透视变换
Sep 20 Python
python 删除系统中的文件(按时间,大小,扩展名)
Nov 19 Python
anaconda升级sklearn版本的实现方法
Feb 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脚本
2006/11/26 PHP
解析thinkphp中的M()与D()方法的区别
2013/06/22 PHP
Laravel框架中Blade模板的用法示例
2017/08/30 PHP
Laravel 连接(Join)示例
2019/10/16 PHP
javascript StringBuilder类实现
2008/12/22 Javascript
js实现简单登录功能的实例代码
2013/11/09 Javascript
JavaScript 判断用户输入的邮箱及手机格式是否正确
2013/12/08 Javascript
jquery 实现输入邮箱时自动补全下拉提示功能
2015/10/04 Javascript
bootstrap-wysiwyg结合ajax实现图片上传实时刷新功能
2016/05/27 Javascript
详解JS-- 浮点数运算处理
2016/11/28 Javascript
jquery事件与绑定事件
2017/03/16 Javascript
使用jQuery和ajax代替iframe的方法(详解)
2017/04/12 jQuery
微信小程序 支付后台java实现实例
2017/05/09 Javascript
node.js处理前端提交的GET请求
2019/08/30 Javascript
vue elementUI 表单校验的实现代码(多层嵌套)
2019/11/06 Javascript
JS如何在数组指定位置插入元素
2020/03/10 Javascript
[01:43]3.19DOTA2发布会 三代刀塔人第三代
2014/03/25 DOTA
[46:00]Ti4 冒泡赛第二轮LGD vs C9 2
2014/07/14 DOTA
[48:51]完美世界DOTA2联赛PWL S2 Magma vs InkIce 第一场 11.28
2020/12/02 DOTA
Python脚本简单实现打开默认浏览器登录人人和打开QQ的方法
2016/04/12 Python
基于 Django 的手机管理系统实现过程详解
2019/08/16 Python
Python爬取知乎图片代码实现解析
2019/09/17 Python
Pytorch中index_select() 函数的实现理解
2019/11/19 Python
Python接口测试数据库封装实现原理
2020/05/09 Python
python numpy库np.percentile用法说明
2020/06/08 Python
详解基于python的全局与局部序列比对的实现(DNA)
2020/10/07 Python
Python __slots__的使用方法
2020/11/15 Python
python如何获得list或numpy数组中最大元素对应的索引
2020/11/16 Python
CSS3属性box-sizing使用指南
2014/12/09 HTML / CSS
JSP和EJB可以共享HttpSession么?EJB里面可以改变session里面的内容
2013/06/05 面试题
学生会主席事迹材料
2014/01/28 职场文书
面试必问:圣杯布局和双飞翼布局的区别
2021/05/13 HTML / CSS
Python基础之条件语句详解
2021/06/16 Python
Apache Linkis 中间件架构及快速安装步骤
2022/03/16 Servers
Python Matplotlib绘制两个Y轴图像
2022/04/13 Python
tomcat下部署jenkins的方法
2022/05/06 Servers