1. 程式人生 > 程式設計 >在 Python 中使用 7zip 備份檔案的操作

在 Python 中使用 7zip 備份檔案的操作

我在按照 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,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','7zip archive'),('bztar','ZIP file')]

通過註冊我們看到,shutil已經支援7z檔案的解壓了,就是如此簡單。

以上為個人經驗,希望能給大家一個參考,也希望大家多多支援我們。如有錯誤或未考慮完全的地方歡迎留言討論,望不吝賜教。