在 Python 中使用 7zip 备份文件的操作


Posted in Python onDecember 11, 2020

我在按照 Byte of python一步步的学习Python, 在学到‘解决方案'的时候,原文的实例 “backup_ver1.py” 是用zip备份文件。

这里面我有几点不一样的地方:

我的电脑没有zip,我用的是7zip;

原文直接用‘zip'命令备份,我直接使用7z命令报错。

使用7z命令备份之前,需要把7zip的安装目录添加到系统环境变量Path中;这时候我可以在CMD中执行7z,但是在python中还是报错,“7z is not recognized as an internal ……”

下面三种方法可以在python中正确运行7z命令:

# 方法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所在的目录

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,递归会把folder同级的其它目录下的文件一起压缩;

在解压的时候,使用-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)

补充知识:谁说Python的shutil不支持7z解压缩,我来教你扩展它的功能!

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[, οnerrοr=None[, followlinks=False]]]) top -- 是你所要遍历的目录的地址, 返回的是一个三元组(root,dirs,files)。

root 所指的是当前正在遍历的这个文件夹的本身的地址

dirs 是一个 list ,内容是该文件夹中所有的目录的名字(不包括子目录)

files 同样是 list , 内容是该文件夹中所有的文件(不包括子目录)

topdown --可选,为 True,则优先遍历 top 目录,否则优先遍历 top 的子目录(默认为开启)。如果 topdown 参数为 True,walk 会遍历top文件夹,与top 文件夹中每一个子目录。

onerror -- 可选,需要一个 callable 对象,当 walk 需要异常时,会调用。

followlinks -- 可选,如果为 True,则会遍历目录下的快捷方式(linux 下是软连接 symbolic link )实际所指的目录(默认关闭),如果为 False,则优先遍历 top 的子目录。

只需要将topdown设置为False,这样在遍历目录时,就会从根节点进行遍历,然后我们逐个删除就ok了,哪里需要那么麻烦!代码如下:

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呢?让我们先来看看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的文件,why?因为专利啊...

RAR是一种专利文件格式,用于数据压缩与归档打包,开发者为尤金·罗谢尔(俄语:Евгений Лазаревич Рошал,拉丁转写:Yevgeny Lazarevich Roshal),RAR的全名是“Roshal ARchive”,即“罗谢尔的归档”之意。首个公开版本RAR 1.3发布于1993年。

所以,有很多产品在软件发布时,开始使用一种压缩率更高的.7z文件,这又是为什么?来让我们访问一下7-zip的官网:7-zip官方主页:https://sparanoid.com/lab/7z/在其中有一个许可协议是这样写的

许可协议:

7-Zip 是一款 开源 软件。大多数源代码都基于 GNU LGPL 许可协议下发布。AES 代码基于 BSD 许可下发布。unRAR 代码基于两种许可:GNU LGPL 和 unRAR 限制许可。更多下许可信息请查看:7-Zip 许可。您可以在任何一台计算机上使用 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文件的解压了,就是如此简单。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持三水点靠木。如有错误或未考虑完全的地方欢迎留言讨论,望不吝赐教。

Python 相关文章推荐
Python实现的一个简单LRU cache
Sep 26 Python
菜鸟使用python实现正则检测密码合法性
Jan 05 Python
python爬虫入门教程--HTML文本的解析库BeautifulSoup(四)
May 25 Python
Python实现GUI学生信息管理系统
Apr 05 Python
我就是这样学习Python中的列表
Jun 02 Python
Python中的asyncio代码详解
Jun 10 Python
wxPython+Matplotlib绘制折线图表
Nov 19 Python
Python中实现输入超时及如何通过变量获取变量名
Jan 18 Python
浅谈Python 参数与变量
Jun 20 Python
利用Python实现斐波那契数列的方法实例
Jul 26 Python
Python使用grequests并发发送请求的示例
Nov 05 Python
宝塔更新Python及Flask项目的部署
Apr 11 Python
Python文件名匹配与文件复制的实现
Dec 11 #Python
Python: glob匹配文件的操作
Dec 11 #Python
Python Socket多线程并发原理及实现
Dec 11 #Python
python 实现Harris角点检测算法
Dec 11 #Python
使用python画出逻辑斯蒂映射(logistic map)中的分叉图案例
Dec 11 #Python
Python3 用matplotlib绘制sigmoid函数的案例
Dec 11 #Python
python 基于opencv 实现一个鼠标绘图小程序
Dec 11 #Python
You might like
咖啡磨器 如何选购一台适合家用的意式磨豆机
2021/03/05 新手入门
linux下 C语言对 php 扩展
2008/12/14 PHP
php 随机记录mysql rand()造成CPU 100%的解决办法
2010/05/18 PHP
PHP微信刮刮卡 附微信接口
2016/07/22 PHP
Javascript 获取LI里的内容
2008/12/17 Javascript
JAVASCRIPT实现的WEB页面跳转以及页面间传值方法
2010/05/13 Javascript
拥抱模块化的JavaScript
2012/03/07 Javascript
javascript 获取iframe里页面中元素值的方法
2014/02/17 Javascript
基于jquery实现导航菜单高亮显示(两种方法)
2015/08/23 Javascript
Web Uploader文件上传插件使用详解
2016/05/10 Javascript
jQuery图片渐变特效的简单实现
2016/06/25 Javascript
微信小程序 chooseImage选择图片或者拍照
2017/04/07 Javascript
基于iScroll实现下拉刷新和上滑加载效果
2017/07/18 Javascript
ES6中的Promise代码详解
2017/10/09 Javascript
浅析Visual Studio Code断点调试Vue
2018/02/27 Javascript
video.js 一个页面同时播放多个视频的实例代码
2018/11/27 Javascript
vue history 模式打包部署在域名的二级目录的配置指南
2019/07/02 Javascript
JavaScript使用表单元素验证表单的示例代码
2019/08/20 Javascript
vue 实现tab切换保持数据状态
2020/07/21 Javascript
微信小程序自定义底部弹出框功能
2020/11/18 Javascript
在Python的Django框架中编写编译函数
2015/07/20 Python
Python语言生成水仙花数代码示例
2017/12/18 Python
python与caffe改变通道顺序的方法
2018/08/04 Python
对pandas中iloc,loc取数据差别及按条件取值的方法详解
2018/11/06 Python
python 多个参数不为空校验方法
2019/02/14 Python
Django ORM 查询表中某列字段值的方法
2020/04/30 Python
通过代码实例了解Python异常本质
2020/09/16 Python
完美解决torch.cuda.is_available()一直返回False的玄学方法
2021/02/06 Python
CSS3+DIV实现漂亮的动画彩色标签
2016/06/16 HTML / CSS
世界领先的豪华床上用品供应商之一:Bedeck Home
2019/03/18 全球购物
《我为你骄傲》教学反思
2014/02/20 职场文书
建房协议书
2014/04/11 职场文书
机械设计专业大学生职业生涯规划书范文
2014/09/13 职场文书
解除同居协议书
2015/01/29 职场文书
面试通知邮件
2015/04/20 职场文书
Python 可迭代对象 iterable的具体使用
2021/08/07 Python