Python实现网站文件的全备份和差异备份

Leo
Leo
发布时间:2026-10-12 | 1人浏览过
原创

本文介绍使用Python实现网站文件的全备份与差异备份方案。针对MD5校验在软连接、空目录及权限变更上的局限性,提出基于文件mtime和ctime的时间戳对比方法。通过Python脚本自动记录文件状态,实现高效的全量打包与增量更新备份,并附带测试用例及处理删除文件的优化建议。

此前曾探讨过利用MD5值进行差异备份的方法,然而该方式在实际应用中暴露出若干缺陷:

• 使用md5sum获取某些软链接的MD5值时存在异常。\n\n• 无法对空目录执行备份,因为md5sum无法计算空目录的MD5值。\n\n• 当文件权限发生修改时,md5sum无法识别此类变更。\n\n\n解决方案:\n\n\n采用文件的mtime和ctime机制。\n\n\nmtime(Modified time)指文件内容被写入时更新的时间戳。\n\nctime(Create time)指文件元数据(如所有者、权限或链接设置)发生更改时,随Inode内容更新而变更的时间戳。\n\n以下直接展示相关代码实现:

#!/usr/bin/env python
import time,os,sys,cPickle

fileInfo = {}

def logger(time,fileName,status,fileNum):
  f = open('backup.log','a')
  f.write("%s\t%s\t%s\t\t%s\n" % (time,fileName,status,fileNum))

def tar(sDir,dDir,fileNum):
  command = "tar zcf %s %s >/dev/null 2>&1" % (dDir + ".tar.gz",sDir)
  if os.system(command) == 0:
    logger(time.strftime('%F %X'),dDir + ".tar.gz",'success',fileNum)
  else:
    logger(time.strftime('%F %X'),dDir + ".tar.gz",'failed',fileNum)

def fullBak(path):
  fileNum = 0
  for root,dirs,files in os.walk(path):
    for name in files:
      file = os.path.join(root, name)
      mtime = os.path.getmtime(file)
      ctime = os.path.getctime(file)
      fileInfo[file] = (mtime,ctime)
      fileNum += 1
  f = open(P,'w')
  cPickle.dump(fileInfo,f)
  f.close()
  tar(S,D,fileNum)

def diffBak(path):
  for root,dirs,files in os.walk(path):
    for name in files:
      file = os.path.join(root,name)
      mtime = os.path.getmtime(file)
      ctime = os.path.getctime(file)
      fileInfo[file] = (mtime,ctime)

  if os.path.isfile(P) == 0:
    f = open(P,'w')
    f.close()

  if os.stat(P).st_size == 0:
    f = open(P,'w')
    cPickle.dump(fileInfo,f)
    fileNum = len(fileInfo.keys())
    f.close()
    print fileNum
    tar(S,D,fileNum)
  else:
    f = open(P)
    old_fileInfo = cPickle.load(f)
    f.close()
    difference = dict(set(fileInfo.items())^set(old_fileInfo.items()))
    fileNum = len(difference)
    print fileNum

    difference_file = ' '.join(difference.keys())
    print difference_file

    tar(difference_file,D,fileNum)
    f = open(P,'w')
    cPickle.dump(fileInfo,f)
    f.close()

def Usage():
  print '''
    Syntax: python file_bakcup.py pickle_file model source_dir filename_bk
      model: 1:Full backup 2:Differential backup

    example: python file_backup.py fileinfo.pk 2 /etc etc_$(date +%F)
      explain: Automatically add '.tar.gz' suffix
  '''
  sys.exit()

if len(sys.argv) != 5:
  Usage()

P = sys.argv[1]
M = int(sys.argv[2])
S = sys.argv[3]
D = sys.argv[4]

if M == 1:
  fullBak(S)
elif M == 2:
  diffBak(S)
else:
  print "\033[;31mDoes not support this mode\033[0m"
  Usage()

测试场景如下:

$ python file_backup.py data.pk 1 data data_$(date +%F) #全备份
$ > data/www.jb51.net #测试创建文件,修改文件权限
$ chmod 777 data/py/eshop_bk/data.db
$ python file_backup.py data.pk 2 data data_$(date +%F)_1 #备份改变的文件
2
data/py/eshop_bk/data.db data/www.jb51.net

参考上述代码获得了启发,但需注意一个潜在问题:若在全量备份后删除了某个文件,随后进行差异备份时,脚本能检测到该文件的缺失,但在执行tar打包时会因文件不存在而报错。因此,在执行tar之前,建议先通过os.path.exists()检查差异文件路径是否存在;若文件已删除,则跳过tar操作,并反馈文件已删除的信息。

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表