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通过加号运算符操作列表的方法
Jul 28 Python
Python中字符串的常见操作技巧总结
Jul 28 Python
python字典多键值及重复键值的使用方法(详解)
Oct 31 Python
python下如何查询CS反恐精英的服务器信息
Jan 17 Python
Python正则表达式教程之二:捕获篇
Mar 02 Python
Python IDLE入门简介
Dec 08 Python
Python队列RabbitMQ 使用方法实例记录
Aug 05 Python
Python any()函数的使用方法
Oct 28 Python
python3.7通过thrift操作hbase的示例代码
Jan 14 Python
Python random模块制作简易的四位数验证码
Feb 01 Python
python-sys.stdout作为默认函数参数的实现
Feb 21 Python
tensorflow 动态获取 BatchSzie 的大小实例
Jun 30 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实现文件下载(支持中文文名)
2013/12/04 PHP
php环境无法上传文件的解决方法
2014/04/30 PHP
浅谈PHP的反射机制
2016/12/15 PHP
Apache+PHP+MySQL搭建PHP开发环境图文教程
2020/08/06 PHP
各浏览器中querySelector和querySelectorAll的实现差异分析
2012/05/23 Javascript
jQuery实现id模糊查询的小例子
2013/03/19 Javascript
js中 关于undefined和null的区别介绍
2013/04/16 Javascript
jquery控制select的text/value值为选中状态
2014/06/03 Javascript
jQuery标签替换函数replaceWith()的使用例子
2014/08/28 Javascript
javascript实现在下拉列表中显示多级树形菜单的方法
2015/08/12 Javascript
跟我学习JScript的Bug与内存管理
2015/11/18 Javascript
jQuery过滤选择器经典应用
2016/08/18 Javascript
JS实现图片局部放大或缩小的方法
2016/08/20 Javascript
Jquery EasyUI $.Parser
2017/06/02 jQuery
Vue 过滤器filters及基本用法
2017/12/26 Javascript
vue+element的表格实现批量删除功能示例代码
2018/08/17 Javascript
Vue实现数据表格合并列rowspan效果
2020/11/30 Javascript
JS实现的碰撞检测与周期移动完整示例
2019/09/02 Javascript
微信小程序表单验证插件WxValidate的二次封装功能(终极版)
2019/09/03 Javascript
UEditor 自定义图片视频尺寸校验功能的实现代码
2020/10/20 Javascript
[43:43]完美世界DOTA2联赛PWL S2 LBZS vs Forest 第三场 11.29
2020/12/02 DOTA
Python中的特殊语法:filter、map、reduce、lambda介绍
2015/04/14 Python
构建Python包的五个简单准则简介
2015/06/15 Python
Python数据集切分实例
2018/12/08 Python
Python实现判断一个整数是否为回文数算法示例
2019/03/02 Python
python可视化实现KNN算法
2019/10/16 Python
python“静态”变量、实例变量与本地变量的声明示例
2020/11/13 Python
全球地下的服装和态度:Slam Jam
2018/02/04 全球购物
美国第一大药店连锁机构:Walgreens(沃尔格林)
2019/10/10 全球购物
C#如何调用Windows程序打开一个文档
2014/12/26 面试题
六一儿童节主持词
2014/03/21 职场文书
法定代表人授权委托书
2014/04/04 职场文书
入党积极分子对十八届四中全会期盼的思想汇报
2014/10/17 职场文书
小学四年级学生评语
2014/12/26 职场文书
降价通知函
2015/04/23 职场文书
win10系统xps文件怎么打开?win10打开xps文件的两种操作方法
2022/07/23 数码科技