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 yield 小结和实例
Apr 25 Python
python脚本实现分析dns日志并对受访域名排行
Sep 18 Python
Python中返回字典键的值的values()方法使用
May 22 Python
python web基础之加载静态文件实例
Mar 20 Python
Anaconda2 5.2.0安装使用图文教程
Sep 19 Python
利用python实现简易版的贪吃蛇游戏(面向python小白)
Dec 30 Python
pandas 使用均值填充缺失值列的小技巧分享
Jul 04 Python
Python 正则表达式爬虫使用案例解析
Sep 23 Python
python redis 批量设置过期key过程解析
Nov 26 Python
Django3.0 异步通信初体验(小结)
Dec 04 Python
pytorch 实现删除tensor中的指定行列
Jan 13 Python
Python 使用xlwt模块将多行多列数据循环写入excel文档的操作
Nov 10 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生成数组再传给js的方法
2014/08/07 PHP
在php7中MongoDB实现模糊查询的方法详解
2017/05/03 PHP
Laravel 批量更新多条数据的示例
2017/11/27 PHP
IE和Firefox在JavaScript应用中的兼容性探讨
2008/04/01 Javascript
用jQuery实现一些导航条切换,显示隐藏的实例代码
2013/06/08 Javascript
javascript中普通函数的使用介绍
2013/12/19 Javascript
js使用正则实现ReplaceAll全部替换的方法
2014/07/18 Javascript
iframe如何动态创建及释放其所占内存
2014/09/03 Javascript
Javascript 拖拽雏形中的一些问题(逐行分析代码,让你轻松了拖拽的原理)
2015/01/23 Javascript
JavaScript中通过prototype属性共享属性和方法的技巧实例
2015/03/13 Javascript
JavaScript中的各种操作符使用总结
2016/05/26 Javascript
tablesorter.js表格排序使用方法(支持中文排序)
2017/02/10 Javascript
javascript过滤数组重复元素的实现方法
2017/05/03 Javascript
AngularJS 表单验证手机号的实例(非必填)
2017/11/12 Javascript
Vue使用mixins实现压缩图片代码
2018/03/14 Javascript
深入分析element ScrollBar滚动组件源码
2019/01/22 Javascript
微信小程序之数据绑定原理解析
2019/08/14 Javascript
在vue中给后台接口传的值为数组的格式代码
2020/11/12 Javascript
node脚手架搭建服务器实现token验证的方法
2021/01/20 Javascript
[01:03:33]Alliance vs TNC 2019国际邀请赛小组赛 BO2 第一场 8.16
2019/08/18 DOTA
[01:06:18]DOTA2-DPC中国联赛 正赛 Phoenix vs Dynasty BO3 第二场 1月26日
2021/03/11 DOTA
Python遍历文件夹和读写文件的实现代码
2016/08/28 Python
R语言 vs Python对比:数据分析哪家强?
2017/11/17 Python
Python读取Json字典写入Excel表格的方法
2018/01/03 Python
Python 二叉树的层序建立与三种遍历实现详解
2019/07/29 Python
使用Python中tkinter库简单gui界面制作及打包成exe的操作方法(二)
2020/10/12 Python
程序设计HTML5 Canvas API
2013/04/08 HTML / CSS
英国最大的电子产品和家电零售企业:Currys PC World
2016/09/24 全球购物
印尼网上商店:Alfacart.com
2019/03/11 全球购物
意大利在线药房:Farmacia Loreto Gallo
2019/08/09 全球购物
导游实习生自荐书
2014/01/28 职场文书
竞选大队委员演讲稿
2014/04/28 职场文书
酒店总经理岗位职责范本
2014/08/08 职场文书
党员批评与自我批评发言材料
2014/10/14 职场文书
nodejs利用readline提示输入内容实例代码
2021/07/15 NodeJs
Python使用华为API为图像设置多个锚点标签
2022/04/12 Python