任務
如果你想在改寫某文件之前對其做個備份,可以在老文件的名字后面根據慣例加上三個數字的版本號。
解決方案
我們需要編寫一個函數來完成備份工作:
def VersionFile(file_spec, vtype='copy'):import os,shutilif os.path.isfile(file_spec):#檢查'vtype'參數if vtype not in('copy','rename'):raise ValueError,'Unknown vtype %r' % (vtype,)#確定根文件名,所以擴展名不會太長n,e = os.path.splitext(file_spec)#是不是一個以點為前導的三個數字?if len(e) == 4 and e[1:].isdigit():num = 1+int(e[1:])root = nelse:num = 0root = file_spec#尋找下一個可用的文件版本for i in xrange(num,1000):new_file = '%s.%03d' %(root,i)if not os.path.exists(new_file):if vtype =='copy':shutil.copy(file_spec,new_file)else:os.rename(file_spec,new_file)return Trueraise RuntimeError,"Can't$s%r,all names taken"%(vtype,file_spec)return False
if __name__ == '__main__':import os#創建一個test.txt文件tfn = 'test.txt'open(tfn,"w').close()#對它取3次版本print VersionFile(tfn)#輸出:Trueprint VersionFile(tfn)# 輸出:Trueprint VersionFile(tfn)#輸出:True#刪除我們剛剛生成的test.txt*文件for x in(''.'.000','.001','.002'):os.unlink(tfn + x)#展示當文件不存在時取版本操作的結果print VersionFile(tfn)#輸出:Falseprint VersionFile(tfn)#輸出:False
討論
VersionFile 函數是為了確保在打開文件進行寫入或更新等修改前,對已存在的目標文件完成了備份(或者重命名,由可選的第二個參數來決定)。在處理文件之前進行備份是很明智的舉措(這也是一些人仍然懷念舊的 VMS操作系統的原因,這種備份是自動進行的)。實際的復制和重命名是分別由shutil.copy和 os.rename 完成的,所以唯一的問題是,怎么確定文件的名字。
一個流行的決定備份的名字的方法是使之版本化(比如,給文件名增加一個逐漸增大的數字)。本節確定文件名的方法是,首先從文件名中分解出名字根(因為有可能這已經是一個版本化的文件名了),然后在這個名字根之后添加進一步的擴展名,比如.000,.001,等等,直到以此種命名方式確定的文件名也無法對應任何一個存在的文件。注意,VersionFile 被限制為只能有1000個版本,所以需要有個歸檔備份的計劃。在進行版本化之前,首先要確保該文件存在–不能對不存在的東西進行備份。如果文件不存在,VersionFile 函數只是簡單地返回 False(如果文件存在而且函數執行無誤則返回 True),所以在調用之前也無須檢査文件是否存在。