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 strip() 函数和 split() 函数的详解及实例
Feb 03 Python
Python实现字符串格式化输出的方法详解
Sep 20 Python
从头学Python之编写可执行的.py文件
Nov 28 Python
Python下调用Linux的Shell命令的方法
Jun 12 Python
python3实现SMTP发送邮件详细教程
Jun 19 Python
详解Python中的type和object
Aug 15 Python
对python遍历文件夹中的所有jpg文件的实例详解
Dec 08 Python
对Python生成汉字字库文字,以及转换为文字图片的实例详解
Jan 29 Python
Python 脚本的三种执行方式小结
Dec 21 Python
Python实现获取当前目录下文件名代码详解
Mar 10 Python
Python中socket网络通信是干嘛的
May 27 Python
python对输出的奇数偶数排序实例代码
Dec 04 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
Terran建筑一览
2020/03/14 星际争霸
php中的一个中文字符串截取函数
2007/02/14 PHP
CodeIgniter框架URL路由总结
2014/09/03 PHP
php实现递归的三种基本方式
2020/07/04 PHP
PHP实现简单的模板引擎功能示例
2017/09/02 PHP
Laravel路由研究之domain解决多域名问题的方法示例
2019/04/04 PHP
php与阿里云短信接口接入操作案例分析
2020/05/27 PHP
用javascript实现点击链接弹出&quot;图片另存为&quot;而不是直接打开
2007/08/15 Javascript
在UpdatePanel内jquery easyui效果失效的解决方法
2010/04/11 Javascript
一些主流JS框架中DOMReady事件的实现小结
2011/02/12 Javascript
JQuery.closest(),parent(),parents()寻找父结点
2012/02/17 Javascript
用js实现in_array的方法
2013/11/05 Javascript
详谈javascript中DOM的基本属性
2015/02/26 Javascript
Avalon中文长字符截取、关键字符隐藏、自定义过滤器
2016/05/18 Javascript
浅谈JS的基础类型与引用类型
2016/09/13 Javascript
jQuery中delegate()方法的用法详解
2016/10/13 Javascript
浅谈React和Redux的连接react-redux
2017/12/04 Javascript
深入理解es6块级作用域的使用
2019/03/28 Javascript
jQuery中DOM操作原则实例分析
2019/08/01 jQuery
Vue使用vue-recoure + http-proxy-middleware + vuex配合promise实现基本的跨域请求封装
2019/10/21 Javascript
原生js实现下拉选项卡
2019/11/27 Javascript
vue开发简单上传图片功能
2020/06/30 Javascript
vue+element-ui JYAdmin后台管理系统模板解析
2020/07/28 Javascript
[01:23:24]DOTA2-DPC中国联赛 正赛 PSG.LGD vs Elephant BO3 第三场 2月7日
2021/03/11 DOTA
python中文分词库jieba使用方法详解
2020/02/11 Python
Windows下实现将Pascal VOC转化为TFRecords
2020/02/17 Python
HTML5不支持frameset的两种解决方法
2016/11/14 HTML / CSS
美国百货齐全的精品网站,提供美式风格的产品:Overstock.com
2016/07/22 全球购物
请解释流与文件有什么不同
2016/07/29 面试题
汽车检测与维修应届毕业生求职信
2013/10/19 职场文书
计算机专业大学生的自我评价
2013/11/14 职场文书
优秀女职工事迹材料
2014/02/06 职场文书
奉献演讲稿范文
2014/05/21 职场文书
MySQL实例精讲单行函数以及字符数学日期流程控制
2021/10/15 MySQL
redis lua限流算法实现示例
2022/07/15 Redis
JS前端轻量fabric.js系列之画布初始化
2022/08/05 Javascript