在 Python 中使用 7zip 備份文件的操作
我在按照 Byte of python一步步的學(xué)習(xí)Python, 在學(xué)到‘解決方案’的時(shí)候,原文的實(shí)例 “backup_ver1.py” 是用zip備份文件。
這里面我有幾點(diǎn)不一樣的地方:
我的電腦沒(méi)有zip,我用的是7zip;
原文直接用‘zip’命令備份,我直接使用7z命令報(bào)錯(cuò)。
使用7z命令備份之前,需要把7zip的安裝目錄添加到系統(tǒng)環(huán)境變量Path中;這時(shí)候我可以在CMD中執(zhí)行7z,但是在python中還是報(bào)錯(cuò),“7z is not recognized as an internal ……”
下面三種方法可以在python中正確運(yùn)行7z命令:
# 方法1: 拷貝 7z.exe 和7z.dll 到當(dāng)前python文件所在的目錄下。 否則,不認(rèn)識(shí)7z 命令。
zip_command = ’7z a -tzip {0} {1} -r’.format(target, ’ ’.join(source))
# 方法2: os.system() 里面執(zhí)行的是同目錄下的exe, 使用如下os.chdir() 命令切換 path。
os.chdir(’D:Program Files (x86)7-Zip’)print(’切換當(dāng)前路徑為:’, 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-Zip7z.exe' a -tzip {0} {1} ’.format(target, ’ ’.join(source))
import osimport time # 1. 需要備份的文件與目錄將被指定在一個(gè)列表中。# 例如在 Windows 下:source = [’'C:My Documents'’, ’C:Code’]# 又例如在 Mac OS X 與 Linux 下:source = [’/Users/swa/notes’]source = [’D:testfold’]# 在這里要注意到我們必須在字符串中使用雙引號(hào)用以括起其中包含空格的名稱。 # 2. 備份文件必須存儲(chǔ)在一個(gè)主備份目錄中# 例如在 Windows 下:target_dir = ’E:Backup’# 又例如在 Mac OS X 和 Linux 下:target_dir = ’/Users/swa/backup’target_dir = ’D:testBackup’# 要記得將這里的目錄地址修改至你將使用的路徑 # 3. 備份文件將打包壓縮成 zip 文件。# 4. zip 壓縮文件的文件名由當(dāng)前日期與時(shí)間構(gòu)成。# os.sep 變量的使用方式——它將根據(jù)你的操作系統(tǒng)給出相應(yīng)的分隔符,在# GNU/Linux 與 Unix 中它會(huì)是 ’/’ ,在 Windows 中它會(huì)是 ’’ ,在 Mac OS 中它會(huì)是 ’:’target = target_dir + os.sep + time.strftime(’%Y%m%d%H%M%S’) + ’.zip’ # 如果目標(biāo)目錄還不存在,則進(jìn)行創(chuàng)建if not os.path.exists(target_dir): os.mkdir(target_dir) # 5. 我們使用 zip 命令將文件打包成 zip 格式# 方法1: 拷貝 7z.exe 和7z.dll 到當(dāng)前python文件所在的目錄下。 否則,不認(rèn)識(shí)7z 命令。# zip_command = ’7z a -tzip {0} {1} -r’.format(target, ’ ’.join(source)) # 方法2: os.system() 里面執(zhí)行的是同目錄下的exe, 使用如下os.chdir() 命令切換 path。# os.chdir(’D:Program Files (x86)7-Zip’)# print(’切換當(dāng)前路徑為:’, os.getcwd())# zip_command = ’7z a -tzip {0} {1} -r’.format(target, ’ ’.join(source)) # 方法3:在cmd 命令中寫入7z.exe所在的目錄# -mcu 強(qiáng)制使用utf-8 編碼文件名zip_command = ’'D:Program Files (x86)7-Zip7z.exe' a -tzip -mcu {0} {1} ’.format(target, ’ ’.join(source))# 運(yùn)行備份print(’nZip command is:’)print(zip_command)print(’Running:’) if os.system(zip_command) == 0: print(’Successful backup to’, target)else: print(’Backup FAILED’) # 查看壓縮文件內(nèi)容check_command = ’'D:Program Files (x86)7-Zip7z.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-Zip7z.exe' x {0} -oD:testextract -y’.format(target) print(’nExtract command is:’)print(extr_command)print(’Running:’) if os.system(extr_command) == 0: print(’Successful extract to’, ’D:testextract’)else: print(’Extract FAILED’)
注意:
在壓縮的時(shí)候,不要使用 -r,遞歸會(huì)把folder同級(jí)的其它目錄下的文件一起壓縮;
在解壓的時(shí)候,使用-y,如果當(dāng)前目錄下已存在被解壓的目錄和文件,替換目標(biāo)文件。
zip_command = ’'D:Program Files (x86)7-Zip7z.exe' a -tzip {0} {1} -r’.format(target, ’ ’.join(source))
extr_command = ’'D:Program Files (x86)7-Zip7z.exe' x {0} -oD:testextract -y’.format(target)
補(bǔ)充知識(shí):誰(shuí)說(shuō)Python的shutil不支持7z解壓縮,我來(lái)教你擴(kuò)展它的功能!
python的內(nèi)置模塊
在Python的標(biāo)準(zhǔn)庫(kù)中,有哪些你常用并且覺(jué)得犀利無(wú)比的模塊?不要說(shuō)time、datetime、os、sys。這些模塊常用是常用,但是逼格不夠高啊。舉個(gè)例子,如果你經(jīng)常在LeetCode上刷題,你會(huì)發(fā)現(xiàn)有時(shí)Java、C需要幾十行的算法題,如果Python使用了collections、itertools,可能三四行代碼就結(jié)束了。
shutil的便利
日常的編碼中,常會(huì)涉及到對(duì)文件、目錄等的操作場(chǎng)景,如果我們使用os,可能需要對(duì)文件、文件夾,非空等進(jìn)行逐個(gè)判斷。舉個(gè)例子: 我們現(xiàn)在要?jiǎng)h除一個(gè)目錄,目錄中包含有文件與文件夾,如果使用os模塊,沒(méi)有現(xiàn)成可以使用的函數(shù),需要我們進(jìn)行判斷與分類執(zhí)行。
import os# path是文件的路徑,如果這個(gè)路徑是一個(gè)文件夾,# 則會(huì)拋出OSError的錯(cuò)誤,這時(shí)需用用rmdir()來(lái)刪除os.remove(path)# path是文件夾路徑,注意文件夾需空的才能被刪除os.rmdir(path)
多數(shù)初學(xué)者遇到刪除文件夾,想到的操作就是,創(chuàng)建兩個(gè)列表,然后用os.walk遍歷目錄,將文件與文件夾分別存入初始化的兩個(gè)列表中,然后先統(tǒng)一刪除文件,最后刪除文件夾。如果有上面這樣操作的同學(xué),請(qǐng)面壁三分鐘。明顯沒(méi)有好好學(xué)習(xí)os.walk函數(shù)。
os.walk(top[, topdown=True[, οnerrοr=None[, followlinks=False]]]) top -- 是你所要遍歷的目錄的地址, 返回的是一個(gè)三元組(root,dirs,files)。
root 所指的是當(dāng)前正在遍歷的這個(gè)文件夾的本身的地址
dirs 是一個(gè) list ,內(nèi)容是該文件夾中所有的目錄的名字(不包括子目錄)
files 同樣是 list , 內(nèi)容是該文件夾中所有的文件(不包括子目錄)
topdown --可選,為 True,則優(yōu)先遍歷 top 目錄,否則優(yōu)先遍歷 top 的子目錄(默認(rèn)為開啟)。如果 topdown 參數(shù)為 True,walk 會(huì)遍歷top文件夾,與top 文件夾中每一個(gè)子目錄。
onerror -- 可選,需要一個(gè) callable 對(duì)象,當(dāng) walk 需要異常時(shí),會(huì)調(diào)用。
followlinks -- 可選,如果為 True,則會(huì)遍歷目錄下的快捷方式(linux 下是軟連接 symbolic link )實(shí)際所指的目錄(默認(rèn)關(guān)閉),如果為 False,則優(yōu)先遍歷 top 的子目錄。
只需要將topdown設(shè)置為False,這樣在遍歷目錄時(shí),就會(huì)從根節(jié)點(diǎn)進(jìn)行遍歷,然后我們逐個(gè)刪除就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))
說(shuō)這么多,無(wú)外乎為了引出最簡(jiǎn)便的方式 : shutil模塊
如果換做shutil模塊登場(chǎng),那么執(zhí)行刪除目錄的操作,只需要0.1秒的時(shí)間:
import shutil
shutil.rmtree(’D:software_temp’)
就這樣,完事兒了...
文件解壓縮
日常工作中,我們經(jīng)常會(huì)使用python進(jìn)行文件的解壓縮處理。python自帶的解壓縮模塊有zipfile, gzip, tarfile,如果我們需要解壓rar文件則需要單獨(dú)下載rarfile模塊,針對(duì)每一種壓縮文件,我們都需要針對(duì)文件類型進(jìn)行對(duì)應(yīng)模塊的使用,是不是很繁瑣?如果我們使用shutil呢?讓我們先來(lái)看看shutil支持的解壓類型:
import pprintimport shutilpprint.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已經(jīng)包含了我們上面提到的所有文件。
.7z文件是什么鬼?
眾所周知,zip的壓縮率相比rar是比較低的,但是商業(yè)軟件下載中,你很少會(huì)見到.rar的文件,why?因?yàn)閷@?..
RAR是一種專利文件格式,用于數(shù)據(jù)壓縮與歸檔打包,開發(fā)者為尤金·羅謝爾(俄語(yǔ):Евгений Лазаревич Рошал,拉丁轉(zhuǎn)寫:Yevgeny Lazarevich Roshal),RAR的全名是“Roshal ARchive”,即“羅謝爾的歸檔”之意。首個(gè)公開版本RAR 1.3發(fā)布于1993年。
所以,有很多產(chǎn)品在軟件發(fā)布時(shí),開始使用一種壓縮率更高的.7z文件,這又是為什么?來(lái)讓我們?cè)L問(wèn)一下7-zip的官網(wǎng):7-zip官方主頁(yè):https://sparanoid.com/lab/7z/在其中有一個(gè)許可協(xié)議是這樣寫的
許可協(xié)議:
7-Zip 是一款 開源 軟件。大多數(shù)源代碼都基于 GNU LGPL 許可協(xié)議下發(fā)布。AES 代碼基于 BSD 許可下發(fā)布。unRAR 代碼基于兩種許可:GNU LGPL 和 unRAR 限制許可。更多下許可信息請(qǐng)查看:7-Zip 許可。您可以在任何一臺(tái)計(jì)算機(jī)上使用 7-Zip ,包括用在商業(yè)用途的計(jì)算機(jī),不對(duì) 7-Zip 進(jìn)行捐贈(zèng)或支付并不影響您的使用。
shutil擴(kuò)展7z
說(shuō)了這么多7z文件的好處,可我們看到shutil并不能解壓該類型的文件啊。我們能否讓shutil支持.7z文件,達(dá)到無(wú)腦解壓縮呢?此時(shí),你需要py7zr模塊。養(yǎng)成好習(xí)慣,遇到模塊先找GitHub:https://github.com/miurahr/py7zr
1. 模塊下載
pip install py7zr
2. 基本使用
當(dāng)我們安裝好py7zr后,它可以在cmd下直接運(yùn)行該命令
List archive contents$ py7zr l test.7zExtract archive$ py7zr x test.7zExtract archive with password$ py7zr x -P test.7z password?: ****Create and compress to archive$ py7zr c target.7z test_dirCreate multi-volume archive$ py7zr c -v 500k target.7z test_dirTest archive$ py7zr t test.7zShow information$ py7zr iShow version$ py7zr --version
單獨(dú)使用模塊
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給大家,不僅因?yàn)樗暮?jiǎn)單好用,更是由于他可以輕松集成于shutil,來(lái)看看它的使用方式吧:
from py7zr import pack_7zarchvie, unpack_7zarchiveimport 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’) # extractionshutil.unpack_archive(’test.7z’, ’/tmp’) # compressionshutil.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’)]
通過(guò)注冊(cè)我們看到,shutil已經(jīng)支持7z文件的解壓了,就是如此簡(jiǎn)單。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持好吧啦網(wǎng)。如有錯(cuò)誤或未考慮完全的地方歡迎留言討論,望不吝賜教。
相關(guān)文章:
