跳转至

7z文件解压、压缩、分包

本文将介绍关于使用py7zr的一些技巧

创建带有加密的7z压缩包

Python
import py7zr  
from py7zr import FILTER_LZMA2

filters = [{'id': FILTER_LZMA2, 'preset': 9}] 
# 这里需要定义解压类型,如果不定义的话,如果使用的类型是极限压缩的话,容易出现编码问题
with open('password', 'r') as f:  
    password = str(f.read())  
# 将密码从文本文档中读取出来,因为默认是列表,所以转换一下
with py7zr.SevenZipFile("D:\\python\\result.7z", mode='r', password=password, filters=filters) as z:  
    z.extractall(path=r'D:\\python\\')

Note

通过目前的测试来看,如果密码含有特殊符号,还是从文档中读取并作为密码,既能贴合现实情况,也能规避一些特殊符号带来的转换问题

Warning

一定要注意压缩文件的编码类型,选择不当会出现问题,还有密码也需要检查清楚,否则会报错,而且都没法看出是哪里出现了问题

压缩分卷解压

如果要对压缩分包进行解压,该如何处理?
Python
import py7zr
# 获取所有压缩分包的名字
filenames = ['example.7z.0001', 'example.7z.0002']
# 将压缩分包合并到一个压缩包中,其中 result.7z是作为中转用的
with open('result.7z', 'ab') as outfile:
    for fname in filenames:
    # 因为压缩包属于二进制文件,所以这里不能用常规的w或r,而是需要用到b
        with open(fname, 'rb') as infile:
            outfile.write(infile.read())
# 正常解压压缩包即可
with py7zr.SevenZipFile("result.7z", "r") as archive:
    archive.extractall()
# 查了一下官方说明,这个和os.remove方法是类似的,主要作用是用来删除中转的文件
os.unlink("result.7z)

1125更新

如果是处理压缩分卷的话,不一定需要像以上那样去合并后处理,可以直接处理,参考代码如下:

Python
def _extract_7z_coiling_file(file_path: str, target_path: str) -> bool:  
    """提取7z压缩分卷"""  
    start_filename_no_suffix: str = os.path.splitext(os.path.basename(file_path))[0]  
    # 不带有后缀名的文件名称  
    try:  
        with multivolumefile.open(  
            os.path.join(os.path.dirname(file_path), start_filename_no_suffix), "rb"  
        ) as target_archive:  
            with SevenZipFile(  
                target_archive,  # type:ignore  
                "r",  
                filters=CommonVariable.filters,  
            ) as archive:  
                archive.extractall(path=target_path)  
        return True  
    except Exception as e:  
        customLogger.info(f"提取7z压缩分卷失败,提示为{e}")  
        return False

创建压缩分卷

如果要对某个文件夹进行压缩分包,该如何处理?
Python
import multivolumefile
import py7zr
import pathlib

target = pathlib.Path('D:\python\python-3.10.6-docs-html')
with multivolumefile.open('example.7z', mode='wb', volume=int(10240*1024/2),) as target_archive:
    with py7zr.SevenZipFile(target_archive, 'w') as archive:
        archive.writeall(target, 'target')

Note

官方手册中的参考代码有问题,现在open传入的参数只能是 volume ,不是 volume_size ,这个只能通过看源代码才能发现,而且 volume 参数默认是按字节进行计算的的,需要注意换算

如果按照上面的代码生成压缩分包,结果生成的压缩分包的编号是4位数,那怎么自定义编号数量了?

通过研究multivolumefile模块,最终发现可以不使用open(),直接调用其类就可以了,参考代码如下:

Python
target = pathlib.Path('D:\python-3.10.6-docs-html')
target_archive=multivolumefile.MultiVolume('example.7z', mode='wb',
volume=int(10240*1024/2),ext_digits=4)
with py7zr.SevenZipFile(target_archive, 'w') as archive:
    archive.writeall(target, 'target')
target_archive.close()

Note

如果想要使用py7zr压缩比较大的文件的话,不建议使用这个模块,经过测试发现它比原生的7-zip要慢上2-3倍,暂时还没有好的解决办法,暂时放在这里做个记录