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 相关文章推荐
将Django框架和遗留的Web应用集成的方法
Jul 24 Python
深入讲解Python中的迭代器和生成器
Oct 26 Python
如何在Python中编写并发程序
Feb 27 Python
Python中字符串的常见操作技巧总结
Jul 28 Python
Python基础知识_浅谈用户交互
May 31 Python
python3+PyQt5+Qt Designer实现扩展对话框
Apr 20 Python
python3+PyQt5实现柱状图
Apr 24 Python
利用python如何在前程无忧高效投递简历
May 07 Python
python中property属性的介绍及其应用详解
Aug 29 Python
自定义Django默认的sitemap站点地图样式
Mar 04 Python
pycharm如何设置官方中文(如何汉化)
Dec 29 Python
python区块链持久化和命令行接口实现简版
May 25 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/10/09 PHP
Zend Framework教程之模型Model用法简单实例
2016/03/04 PHP
php调用自己java程序的方法详解
2016/05/13 PHP
静态html文件执行php语句的方法(推荐)
2016/11/21 PHP
PHP字符串逆序排列实现方法小结【strrev函数,二分法,循环法,递归法】
2017/01/13 PHP
thinkPHP5.0框架安装教程
2017/03/25 PHP
基于Laravel(5.4版本)的基本增删改查操作方法
2019/10/11 PHP
javascript学习笔记(十三) js闭包介绍(转)
2012/06/20 Javascript
Javascript在IE和FireFox中的不同表现简析
2012/12/03 Javascript
网页整体变灰白色(兼容各浏览器)实例
2013/04/21 Javascript
JQuery实现倒计时按钮具体方法
2013/11/14 Javascript
Prototype框架详解
2015/11/25 Javascript
Jquery操作Ajax方法小结
2015/11/29 Javascript
JavaScript encodeURI 和encodeURIComponent
2015/12/04 Javascript
JS加载器如何动态加载外部js文件
2016/05/26 Javascript
JavaScript hasOwnProperty() 函数实例详解
2017/08/04 Javascript
vue中echarts3.0自适应的方法
2018/02/26 Javascript
vue源码解析之事件机制原理
2018/04/21 Javascript
详解vuex结合localstorage动态监听storage的变化
2018/05/03 Javascript
微信小程序wx.uploadfile 本地文件转base64的实现代码
2018/06/28 Javascript
产制造追溯系统之通过微信小程序实现移动端报表平台
2019/06/03 Javascript
微信小程序获取地理位置及经纬度授权代码实例
2019/09/18 Javascript
2分钟实现一个Vue实时直播系统的示例代码
2020/06/05 Javascript
vue插件--仿微信小程序showModel实现模态提示窗功能
2020/08/19 Javascript
JavaScript常用进制转换及位运算实例解析
2020/10/14 Javascript
Python二叉树的镜像转换实现方法示例
2019/03/06 Python
PyQt5实现从主窗口打开子窗口的方法
2019/06/19 Python
详解Django将秒转换为xx天xx时xx分
2019/09/27 Python
Html5 video标签视频的最佳实践
2020/02/26 HTML / CSS
澳大利亚天然护肤品、化妆品和健康产品一站式商店:Nourished Life
2018/12/02 全球购物
德国自行车商店:Tretwerk
2019/06/21 全球购物
商铺门面租房协议书
2014/10/21 职场文书
放假通知
2015/04/14 职场文书
幽默口才训练经典句子(48句)
2019/08/19 职场文书
HTML5中 rem适配方案与 viewport 适配问题详解
2021/04/27 HTML / CSS
Vue实现导入Excel功能步骤详解
2021/07/03 Vue.js