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写一个无界面的2048小游戏
May 24 Python
使用python绘制二元函数图像的实例
Feb 12 Python
Python实现多进程的四种方式
Feb 22 Python
Python提取转移文件夹内所有.jpg文件并查看每一帧的方法
Jun 27 Python
Python实现打印实心和空心菱形
Nov 23 Python
Tensorflow设置显存自适应,显存比例的操作
Feb 03 Python
Python通过4种方式实现进程数据通信
Mar 12 Python
Python sql注入 过滤字符串的非法字符实例
Apr 03 Python
浅谈numpy中np.array()与np.asarray的区别以及.tolist
Jun 03 Python
使用python求斐波那契数列中第n个数的值示例代码
Jul 26 Python
Python如何设置指定窗口为前台活动窗口
Aug 12 Python
Matplotlib绘制混淆矩阵的实现
May 27 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目录管理函数小结
2008/09/10 PHP
php 大数据量及海量数据处理算法总结
2011/05/07 PHP
php header Content-Type类型小结
2011/07/03 PHP
php字符串过滤与替换小结
2015/01/26 PHP
PHP中SESSION的注销与清除
2015/04/16 PHP
Laravel向公共模板赋值方法总结
2019/06/25 PHP
laravel5表单唯一验证的实例代码
2019/09/30 PHP
有关javascript的性能优化 (repaint和reflow)
2013/04/12 Javascript
js图片延迟技术一般的思路与示例
2014/03/20 Javascript
JavaScript对象的property属性详解
2014/04/01 Javascript
JavaScript异步回调的Promise模式封装实例
2014/06/07 Javascript
jquery图片倾斜层叠切换特效代码分享
2015/08/27 Javascript
JavaScript SweetAlert插件实现超酷消息警告框
2016/01/28 Javascript
VUEJS实战之利用laypage插件实现分页(3)
2016/06/13 Javascript
浅谈javascript中的Function和Arguments
2016/08/30 Javascript
利用node.js如何创建子进程详解
2017/12/09 Javascript
js根据json数据中的某一个属性来给数据分组的方法
2018/10/08 Javascript
Nuxt.js nuxt-link与router-link的区别说明
2020/11/06 Javascript
[47:36]Optic vs Newbee 2018国际邀请赛小组赛BO2 第二场 8.17
2018/08/18 DOTA
python中pass语句用法实例分析
2015/04/30 Python
Python虚拟环境项目实例
2017/11/20 Python
Python 数据处理库 pandas 入门教程基本操作
2018/04/19 Python
python利用requests库进行接口测试的方法详解
2018/07/06 Python
Django 使用easy_thumbnails压缩上传的图片方法
2019/07/26 Python
python 协程 gevent原理与用法分析
2019/11/22 Python
Python异常继承关系和自定义异常实现代码实例
2020/02/20 Python
html+css3实现的登录界面
2020/12/09 HTML / CSS
家得宝墨西哥官网:The Home Depot墨西哥
2019/11/18 全球购物
澳大利亚领先的亚麻品牌:Bed Threads
2019/12/16 全球购物
神路信息Java面试题目
2013/03/31 面试题
医疗专业毕业生求职信
2014/08/28 职场文书
优秀党员推荐材料
2014/12/18 职场文书
2015年上半年计生工作总结
2015/03/30 职场文书
现场施工员岗位职责
2015/04/11 职场文书
汉语拼音教学反思
2016/02/22 职场文书
MySQL表字段数量限制及行大小限制详情
2022/07/23 MySQL