任务
如果你想在改写某文件之前对其做个备份,可以在老文件的名字后面根据惯例加上三个数字的版本号。
解决方案
我们需要编写一个函数来完成备份工作:
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),所以在调用之前也无须检査文件是否存在。