Python实现zip分卷压缩

使用 zipfile 库

查看 官方中文文档

利用 Python 压缩 ZIP 文件,我们第一反应是使用 zipfile 库,然而,它的官方文档中却明确标注“此模块目前不能处理分卷 ZIP 文件”,(⊙﹏⊙)

折腾经过

翻遍了Google、CSDN、Stackoverflow等平台均未找到解决方案,最靠谱的是调用外部解压程序实现分卷压缩的功能。但是,如何不依靠外部程序实现这个功能呢??

于是乎,只能自己慢慢造轮子。看着 ZIP 格式开发商留下的文档 ZIP File Format Specification,头疼啊(;´д`)。于是我拿着 WinHex 开始16进制一个一个文件对比 WinRar 创建的分卷压缩和单个 zip 文件的差异。最后还真的整出来了( ̄▽ ̄)"

如果想把单个大文件 test.zip -> 分卷文件 test.z01test.z02test.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 库不支持创建分卷文件了〒▽〒

这个库的作者也没少掉头发。。。现在就将就一下,这样用着吧。。。

Python3实现zip分卷压缩的更多相关文章

  1. linux下分卷压缩,合并解压的3种方法

    我们上传东西的时候,由于文件过大而不能上传,或者不给上传,最明显的就是发邮件了,附件最大5M,有的10M.如果超过了就郁闷了.这个时候,如果能把压缩的东西,分割开来就比较爽了,windows下面我想大 ...

  2. zip命令分卷压缩和解压缩

    创建分卷压缩文件 zip -s 100m -r folder.zip folder/ -s: 创建分卷的大小 -r: 循环压缩文件夹下面的内容 切分已有的文件: zip existing.zip -- ...

  3. Windows下解压分卷压缩方法

    各种压缩分卷格式 rar分卷格式是*.part1.rar,*.part2.rar 等等. 360分卷压缩出来的文件的名字是*.zip.001.*.zip002 等等. WinZip分卷压缩出来的文件名 ...

  4. Zip文件压缩(加密||非加密||压缩指定目录||压缩目录下的单个文件||根据路径压缩||根据流压缩)

    1.写入Excel,并加密压缩.不保存文件 String dcxh = String.format("%03d", keyValue); String folderFileName ...

  5. linux 下 zip unzip压缩与解压

    注:*压缩成限.zip格式文件 常用解压缩: [root@mysql test]# unzip -o test.zip -d tmp/ 将压缩文件test.zip在指定目录tmp下解压缩,如果已有相同 ...

  6. linux下tar、zip等压缩、解压命令

    .tar解包:tar xvf FileName.tar打包:tar cvf FileName.tar DirName(注:tar是打包,不是压缩!)-------------------------- ...

  7. C#执行zip文件压缩的几种方法及我遇到的坑总结

    工作项目中需要用到zip压缩解压缩文件,一开始看上了Ionic.Zip.dll这个类库,操作方便,写法简单 对应有个ziphelper类 using Ionic.Zip; public static ...

  8. 基于ICSharpCode.SharpZipLib.Zip的压缩解压缩

    原文:基于ICSharpCode.SharpZipLib.Zip的压缩解压缩 今天记压缩解压缩的使用,是基于开源项目ICSharpCode.SharpZipLib.Zip的使用. 一.压缩: /// ...

  9. Java用ZIP格式压缩和解压缩文件

    转载:java jdk实例宝典 感觉讲的非常好就转载在这保存! java.util.zip包实现了Zip格式相关的类库,使用格式zip格式压缩和解压缩文件的时候,须要导入该包. 使用zipoutput ...

随机推荐

  1. 为什么我们需要Q#?

    原文地址:https://blogs.msdn.microsoft.com/visualstudio/2018/11/15/why-do-we-need-q/ 本文章为机器翻译. 你可能熟悉微软量子的 ...

  2. Golang | 既是接口又是类型,interface是什么神仙用法?

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是golang专题的第12篇文章,我们来继续聊聊interface的使用. 在上一篇文章当中我们介绍了面向对象的一些基本概念,以及gol ...

  3. Caused by: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for

    Caused by: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value f ...

  4. asp.net core 应用docke部署到centos7

    前言 前期准备 win10 (不要安装hyper-V) VMware-Workstation-Pro/15.0 Xshell6 (非必需) VS2019 以上环境请自行安装 都是默认安装没什么可说的 ...

  5. Springboot + Rabbitmq + WebSocet + vue

    1.pom.xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId& ...

  6. Jmeter系列(46)- Jmeter 中有哪些常用的函数

    如果你想从头学习Jmeter,可以看看这个系列的文章哦 https://www.cnblogs.com/poloyy/category/1746599.html 前言 Jmeter 提供了很多函数 但 ...

  7. web渗透测试之sqlmap拿到数据库信息

    通过扫描我们发现目标网站存在sql注入漏洞,我们访问该里面后发现该网站里面有个表格提交参数.确实存在没有过滤 使用sqlmap扫描发现漏洞的确存在,这里是布尔盲注 查看当前数据库名 查看表名得到以下信 ...

  8. 从 BIO、NIO 聊到 Netty,最后还要实现个 RPC 框架!

    大家好,我是 「后端技术进阶」 作者,一个热爱技术的少年. 觉得不错的话,欢迎 star!ღ( ´・ᴗ・` )比心 Netty 从入门到实战系列文章地址:https://github.com/Snai ...

  9. 你竟然不知道Java中可以用 :: 吗?

    简介 Java8中方法引用分为三种,方法引用通过一对双冒号:: 来表示,方法引用是一种函数式接口的另一种书写方式 静态方法引用,通过类名::静态方法名, 如 Integer::parseInt 实例方 ...

  10. 区块链入门到实战(18)之以太坊(Ethereum) – 什么是智能合约

    作用:提供优于传统合约的安全方法,并减少与合约相关的其他交易成本. 以太坊网络基石:以太坊虚拟币和智能合约. 智能合约(Smart contract )是一种旨在以信息化方式传播.验证或执行合同的计算 ...