Python 调用 7-Zip 备份与解压实战:环境变量配置及 shutil 扩展指南
本文详解在 Python 中调用 7-Zip 进行文件备份与解压的完整流程。涵盖解决“7z 命令未识别”的环境变量配置技巧,包括路径拷贝、os.chdir 切换及绝对路径调用三种方案。同时介绍 os.walk 与 shutil.rmtree 的高效目录删除方法,并通过 py7zr 模块扩展 shutil 以支持 .7z 格式的无缝解压,提供从基础命令到高级封装的实用代码示例。
Python 调用 7-Zip 备份与解压实战
在跟随《Byte of Python》学习 Python 的过程中,我遇到了“解决方案”章节的实例代码“backup_ver1.py”。该示例原本使用 zip 工具进行文件备份。
在实际操作中,我对原示例进行了以下调整:
首先,我的电脑环境中未安装 zip 工具,而是使用了 7-Zip 作为压缩软件。
其次,原示例直接调用‘zip'命令,而我尝试直接替换为‘7z'命令时遇到了报错。
为了让 7z 命令在 Python 中正常运行,必须先将 7-Zip 的安装目录添加到系统环境变量的 Path 中。尽管此时在 CMD 中可以成功执行 7z,但在 Python 脚本中仍会报错,提示“7z is not recognized as an internal or external command”。
以下是三种在 Python 中成功调用 7z 命令的方法:
三种调用 7z 命令的方法
方法一:将 7z.exe 和 7z.dll 文件复制到当前 Python 脚本所在的目录下。这样可以确保 Python 进程能够识别并调用 7z 命令,无需配置环境变量。
zip_command = '7z a -tzip {0} {1} -r'.format(target, ' '.join(source))
方法二:利用 os.system() 执行同目录下的 exe 文件。在使用命令前,通过 os.chdir() 切换当前工作路径至 7-Zip 安装目录。
os.chdir('D:\\Program Files (x86)\\7-Zip')
print('切换当前路径为:', os.getcwd())
zip_command = '7z a -tzip {0} {1} -r'.format(target, ' '.join(source))
方法三:在 CMD 命令字符串中直接写入 7z.exe 的完整绝对路径。
zip_command = '"D:\\Program Files (x86)\\7-Zip\\7z.exe" a -tzip {0} {1} '.format(target, ' '.join(source))
import os
import time
# 1. 需要备份的文件与目录将被指定在一个列表中。
# 例如在 Windows 下:source = ['"C:\\My Documents"', 'C:\\Code']
# 又例如在 Mac OS X 与 Linux 下:source = ['/Users/swa/notes']
source = ['D:\\test\\fold\\']
# 在这里要注意到我们必须在字符串中使用双引号用以括起其中包含空格的名称。
# 2. 备份文件必须存储在一个主备份目录中
# 例如在 Windows 下:target_dir = 'E:\\Backup'
# 又例如在 Mac OS X 和 Linux 下:target_dir = '/Users/swa/backup'
target_dir = 'D:\\test\\Backup'
# 要记得将这里的目录地址修改至你将使用的路径
# 3. 备份文件将打包压缩成 zip 文件。
# 4. zip 压缩文件的文件名由当前日期与时间构成。
# os.sep 变量的使用方式——它将根据你的操作系统给出相应的分隔符,在# GNU/Linux 与 Unix 中它会是 '/' ,在 Windows 中它会是 '\\' ,在 Mac OS 中它会是 ':'
target = target_dir + os.sep + time.strftime('%Y%m%d%H%M%S') + '.zip'
# 如果目标目录还不存在,则进行创建
if not os.path.exists(target_dir):
os.mkdir(target_dir)
# 5. 我们使用 zip 命令将文件打包成 zip 格式
# 方法1: 拷贝 7z.exe 和7z.dll 到当前python文件所在的目录下。 否则,不认识7z 命令。
# zip_command = '7z a -tzip {0} {1} -r'.format(target, ' '.join(source))
# 方法2: os.system() 里面执行的是同目录下的exe, 使用如下os.chdir() 命令切换 path。
# os.chdir('D:\\Program Files (x86)\\7-Zip')
# print('切换当前路径为:', os.getcwd())
# zip_command = '7z a -tzip {0} {1} -r'.format(target, ' '.join(source))
# 方法3:在cmd 命令中写入7z.exe所在的目录
# -mcu 强制使用utf-8 编码文件名
zip_command = '"D:\\Program Files (x86)\\7-Zip\\7z.exe" a -tzip -mcu {0} {1} '.format(target, ' '.join(source))
# 运行备份
print('\nZip command is:')
print(zip_command)
print('Running:')
if os.system(zip_command) == 0:
print('Successful backup to', target)
else:
print('Backup FAILED')
# 查看压缩文件内容
check_command = '"D:\\Program Files (x86)\\7-Zip\\7z.exe" l {0}'.format(target)
print('\nCheck zipfile command is:')
print(check_command)
print('Running:')
# 使用 os.system(check_command) 中文返回有乱码,所以使用 os.popen
# if os.system(check_command) == 0:
# print('Please check the file list in:', target)
# else:
# print('Check info FAILED')
print('Please check the file list in:', target)
p = os.popen(check_command)
print(p.read())
p.close()
# 解压缩到目录
extr_command = '"D:\\Program Files (x86)\\7-Zip\\7z.exe" x {0} -oD:\\test\\extract\\ -y'.format(target)
print('\nExtract command is:')
print(extr_command)
print('Running:')
if os.system(extr_command) == 0:
print('Successful extract to', 'D:\\test\\extract')
else:
print('Extract FAILED')
注意事项:
在压缩操作中,应避免使用 -r 参数。因为 -r 代表递归压缩,这会导致将目标文件夹同级目录下的其他文件一并打包进压缩包,可能不符合预期。
在解压操作中,建议使用 -y 参数。如果目标目录下已存在同名文件或目录,-y 参数会强制覆盖并替换目标文件,避免交互式询问。
zip_command = '"D:\\Program Files (x86)\\7-Zip\\7z.exe" a -tzip {0} {1} -r'.format(target, ' '.join(source))
extr_command = '"D:\\Program Files (x86)\\7-Zip\\7z.exe" x {0} -oD:\\test\\extract\\ -y'.format(target)
shutil 模块扩展与 py7zr 集成
补充知识:关于 Python 的 shutil 模块是否支持 7z 解压缩,可以通过扩展其功能来实现。
Python 内置模块与目录操作优化
Python 内置模块概览
在 Python 的标准库中,有哪些常用且高效的模块?排除 time、datetime、os、sys 等基础模块。例如,在 LeetCode 刷题时,涉及复杂算法的 Java 或 C 语言可能需要几十行代码,而 Python 利用 collections 和 itertools 模块,往往只需三四行即可解决。
shutil 模块的便利性
在日常编码中,文件与目录操作是常见场景。若使用 os 模块,需对文件、文件夹及非空状态进行逐一判断。例如,删除包含文件和子目录的文件夹时,使用 os 模块没有现成的单一函数,需要手动判断并分类执行。
import os
# path是文件的路径,如果这个路径是一个文件夹,
# 则会抛出OSError的错误,这时需用用rmdir()来删除
os.remove(path)
# path是文件夹路径,注意文件夹需空的才能被删除
os.rmdir(path)
许多初学者在删除文件夹时,会创建两个列表,利用 os.walk 遍历目录,将文件与文件夹分别存入列表,先统一删除文件,最后再删除文件夹。若采用此方式,说明对 os.walk 函数的理解尚显不足。
os.walk(top[, topdown=True[, onerror=None[, followlinks=False]]]) 函数中,top 参数指定要遍历的目录地址,返回一个三元组 (root, dirs, files)。
root 表示当前正在遍历的文件夹本身的地址。
dirs 是一个列表,包含该文件夹中所有子目录的名字(不包括子目录内的内容)。
files 同样是一个列表,包含该文件夹中所有文件的名称(不包括子目录)。
topdown 为可选参数,默认为 True。若为 True,则优先遍历 top 目录本身,随后遍历其子目录;若为 False,则优先遍历子目录。
onerror 为可选参数,需提供一个 callable 对象。当 walk 过程中发生异常时,会调用该对象处理错误。
followlinks 为可选参数,默认为 False。若为 True,则会遍历目录下的符号链接(Linux 下)所指向的实际目录;若为 False,则优先遍历 top 的子目录而不跟随链接。
只需将 topdown 设置为 False,遍历将从叶子节点(最深层目录)开始向上进行,从而可以逐个安全删除文件和空目录,无需繁琐的手动分类。代码如下:
import os
for root, dirs, files in os.walk('D:\\software_temp', topdown=False):
for name in files:
os.remove(os.path.join(root, name))
for name in dirs:
os.rmdir(os.path.join(root, name))
上述讨论旨在引出更简便的方式:shutil 模块。
若使用 shutil 模块,执行删除目录的操作仅需极短时间,例如 0.1 秒即可完成:
import shutil
shutil.rmtree('D:\\software_temp')
如此即可轻松完成目录删除操作。
文件解压缩扩展
日常工作中,常需使用 Python 处理文件的解压缩。Python 内置模块包括 zipfile、gzip 和 tarfile。若需解压 rar 文件,则需单独下载 rarfile 模块。针对每种压缩格式,均需调用对应的模块,显得较为繁琐。若使用 shutil,先查看其支持的解压类型:
import pprint
import shutil
pprint.pprint(shutil.get_unpack_formats())
output:
[('bztar', ['.tar.bz2', '.tbz2'], "bzip2'ed tar-file"),
('gztar', ['.tar.gz', '.tgz'], "gzip'ed tar-file"),
('tar', ['.tar'], 'uncompressed tar file'),
('xztar', ['.tar.xz', '.txz'], "xz'ed tar-file"),
('zip', ['.zip'], 'ZIP file')]
shutil 已包含上述提到的所有常见文件格式。
那么 .7z 文件如何处理?
众所周知,zip 的压缩率通常低于 rar。但在商业软件发布中,很少见到 .rar 文件,原因在于专利限制。
RAR 是一种专利文件格式,用于数据压缩与归档打包,开发者为尤金·罗谢尔(Yevgeny Lazarevich Roshal)。RAR 全名为“Roshal ARchive”,即“罗谢尔的归档”。首个公开版本 RAR 1.3 发布于 1993 年。
因此,许多软件在发布时开始使用压缩率更高的 .7z 文件。访问 7-Zip 官网(https://sparanoid.com/lab/7z/)可查看其许可协议。
许可协议说明:
7-Zip 是开源软件,大多数源代码基于 GNU LGPL 许可协议发布。AES 代码基于 BSD 许可发布。unRAR 代码基于 GNU LGPL 和 unRAR 限制许可两种协议。更多信息请查阅 7-Zip 许可页面。用户可在任何计算机上使用 7-Zip,包括商业用途,无需捐赠或付费。
shutil 扩展支持 7z
尽管 7z 文件优势明显,但 shutil 默认并不支持解压该类型文件。如何让 shutil 支持 .7z 文件,实现无脑解压缩?此时需要引入 py7zr 模块。养成查看 GitHub 的习惯:https://github.com/miurahr/py7zr
1. 模块安装
pip install py7zr
2. 基本使用方法
安装好 py7zr 后,可在 CMD 中直接运行相关命令。
List archive contents
$ py7zr l test.7z
Extract archive
$ py7zr x test.7z
Extract archive with password
$ py7zr x -P test.7z
password?: ****
Create and compress to archive
$ py7zr c target.7z test_dir
Create multi-volume archive
$ py7zr c -v 500k target.7z test_dir
Test archive
$ py7zr t test.7z
Show information
$ py7zr i
Show version
$ py7zr --version
单独使用模块示例
import py7zr
archive = py7zr.SevenZipFile('sample.7z', mode='r')
archive.extractall(path="/tmp")
archive.close()
with py7zr.SevenZipFile('target.7z', 'w') as z:
z.writeall('./base_dir')
3. 集成至 shutil
推荐 py7zr 不仅因其简单易用,更因其能轻松集成到 shutil 中。使用方式如下:
from py7zr import pack_7zarchvie, unpack_7zarchive
import shutil
# register file format at first.
shutil.register_archive_format('7zip',
pack_7zarchive,
description='7zip archive')
shutil.register_unpack_format('7zip',
['.7z'],
unpack_7zarchive,
description='7zip archive')
# extraction
shutil.unpack_archive('test.7z', '/tmp')
# compression
shutil.make_archive('target', '7zip', 'src')
pprint.pprint(shutil.get_unpack_formats())
# output:
[('7zip', ['.7z'], '7zip archive'),
('bztar', ['.tar.bz2', '.tbz2'], "bzip2'ed tar-file"),
('gztar', ['.tar.gz', '.tgz'], "gzip'ed tar-file"),
('tar', ['.tar'], 'uncompressed tar file'),
('xztar', ['.tar.xz', '.txz'], "xz'ed tar-file"),
('zip', ['.zip'], 'ZIP file')]
通过注册,shutil 现已支持 7z 文件的解压,操作十分简单。
以上为个人经验分享,希望能为大家提供参考。欢迎留言讨论,如有错误或未考虑周全之处,敬请指正。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









