python实现的一个文件同步模块

简介:
 
  1. """ pyrobocopy.py - 
  2.  
  3.     Version: 1.0 
  4.      
  5.     Report the difference in content 
  6.     of two directories, synchronize or 
  7.     update a directory from another, taking 
  8.     into account time-stamps of files etc. 
  9.  
  10.     By Anand B Pillai  
  11.  
  12.     (This program is inspired by the windows 
  13.     'Robocopy' program.) 
  14.  
  15.     Mod  Nov 11 Rewrote to use the filecmp module. 
  16. """ 
  17.  
  18. import os, stat 
  19. import time 
  20. import shutil 
  21. import filecmp 
  22.  
  23. def usage(): 
  24.     return """ 
  25. Pyrobocopy: Command line directory diff, synchronization, update & copy 
  26.  
  27. Author: Anand Pillai 
  28.  
  29. Usage: %s <sourcedir> <targetdir> Options 
  30.  
  31. Main Options:\n 
  32. \t-d --diff         - Only report difference between sourcedir and targetdir 
  33. \t-s, --synchronize - Synchronize content between sourcedir and targetdir 
  34. \t-u, --update      - Update existing content between sourcedir and targetdir 
  35.  
  36. Additional Options:\n 
  37. \t-p, --purge       - Purge files when synchronizing (does not purge by default). 
  38. \t-f, --force       - Force copying of files, by trying to change file permissions. 
  39. \t-n, --nodirection - Update files in source directory from target 
  40. \t                    directory (only updates target from source by default). 
  41. \t-c, --create      - Create target directory if it does not exist (By default, 
  42. \t                    target directory should exist.) 
  43. \t-m, --modtime     - Only compare file's modification times for an update (By default, 
  44. \t                    compares source file's creation time also). 
  45. """                    
  46.  
  47.  
  48.  
  49. class PyRobocopier: 
  50.     """ An advanced directory synchronization, updation 
  51.     and file copying class """ 
  52.  
  53.     prog_name = "pyrobocopy.py" 
  54.      
  55.     def __init__(self): 
  56.  
  57.         self.__dir1 = '' 
  58.         self.__dir2 = '' 
  59.         self.__dcmp = None 
  60.          
  61.         self.__copyfiles = True 
  62.         self.__forcecopy = False 
  63.         self.__copydirection = 0 
  64.         self.__updatefiles = True 
  65.         self.__creatdirs = True 
  66.         self.__purge =False 
  67.         self.__maketarget =False 
  68.         self.__modtimeonly =False 
  69.         self.__mainfunc = None 
  70.          
  71.         # stat vars 
  72.         self.__numdirs =0 
  73.         self.__numfiles =0 
  74.         self.__numdelfiles =0 
  75.         self.__numdeldirs =0      
  76.         self.__numnewdirs =0 
  77.         self.__numupdates =0 
  78.         self.__starttime = 0.0 
  79.         self.__endtime = 0.0 
  80.          
  81.         # failure stat vars 
  82.         self.__numcopyfld =0 
  83.         self.__numupdsfld =0 
  84.         self.__numdirsfld =0 
  85.         self.__numdelffld  =0 
  86.         self.__numdeldfld  =0 
  87.  
  88.     def parse_args(self, arguments): 
  89.         """ Parse arguments """ 
  90.          
  91.         import getopt 
  92.  
  93.         shortargs = "supncm" 
  94.         longargs = ["synchronize=""update=""purge=""nodirection=""create=""modtime="
  95.  
  96.         try
  97.             optlist, args = getopt.getopt( arguments, shortargs, longargs ) 
  98.         except getopt.GetoptError, e: 
  99.             print e 
  100.             return None 
  101.  
  102.         allargs = [] 
  103.         if len(optlist): 
  104.             allargs = [x[0for x in optlist] 
  105.              
  106.         allargs.extend( args ) 
  107.         self.__setargs( allargs ) 
  108.              
  109.     def __setargs(self, argslist): 
  110.         """ Sets internal variables using arguments """ 
  111.          
  112.         for option in argslist: 
  113.             if option.lower() in ('-s''--synchronize'): 
  114.                 self.__mainfunc = self.synchronize 
  115.             elif option.lower() in ('-u''--update'): 
  116.                 self.__mainfunc = self.update 
  117.             elif option.lower() in ('-d''--diff'): 
  118.                 self.__mainfunc = self.dirdiff 
  119.             elif option.lower() in ('-p''--purge'): 
  120.                 self.__purge = True 
  121.             elif option.lower() in ('-n''--nodirection'): 
  122.                 self.__copydirection = 2 
  123.             elif option.lower() in ('-f''--force'): 
  124.                 self.__forcecopy = True 
  125.             elif option.lower() in ('-c''--create'): 
  126.                 self.__maketarget = True 
  127.             elif option.lower() in ('-m''--modtime'): 
  128.                 self.__modtimeonly = True                             
  129.             else
  130.                 if self.__dir1==''
  131.                     self.__dir1 = option 
  132.                 elif self.__dir2==''
  133.                     self.__dir2 = option 
  134.                  
  135.         if self.__dir1=='' or self.__dir2==''
  136.             sys.exit("Argument Error: Directory arguments not given!"
  137.         if not os.path.isdir(self.__dir1): 
  138.             sys.exit("Argument Error: Source directory does not exist!"
  139.         if not self.__maketarget and not os.path.isdir(self.__dir2): 
  140.             sys.exit("Argument Error: Target directory %s does not exist! (Try the -c option)." % self.__dir2) 
  141.         if self.__mainfunc is None
  142.             sys.exit("Argument Error: Specify an action (Diff, Synchronize or Update) "
  143.  
  144.         self.__dcmp = filecmp.dircmp(self.__dir1, self.__dir2) 
  145.  
  146.     def do_work(self): 
  147.         """ Do work """ 
  148.  
  149.         self.__starttime = time.time() 
  150.          
  151.         if not os.path.isdir(self.__dir2): 
  152.             if self.__maketarget: 
  153.                 print 'Creating directory'self.__dir2 
  154.                 try
  155.                     os.makedirs(self.__dir2) 
  156.                 except Exception, e: 
  157.                     print e 
  158.                     return None 
  159.  
  160.         # All right! 
  161.         self.__mainfunc() 
  162.         self.__endtime = time.time() 
  163.          
  164.     def __dowork(self, dir1, dir2, copyfunc = None, updatefunc = None): 
  165.         """ Private attribute for doing work """ 
  166.          
  167.         print 'Source directory: ', dir1, ':' 
  168.  
  169.         self.__numdirs += 1 
  170.         self.__dcmp = filecmp.dircmp(dir1, dir2) 
  171.          
  172.         # Files & directories only in target directory 
  173.         if self.__purge: 
  174.             for f2 in self.__dcmp.right_only: 
  175.                 fullf2 = os.path.join(dir2, f2) 
  176.                 print 'Deleting ',fullf2 
  177.                 try
  178.                     if os.path.isfile(fullf2): 
  179.                          
  180.                         try
  181.                             os.remove(fullf2) 
  182.                             self.__numdelfiles += 1 
  183.                         except OSError, e: 
  184.                             print e 
  185.                             self.__numdelffld += 1 
  186.                     elif os.path.isdir(fullf2): 
  187.                         try
  188.                             shutil.rmtree( fullf2, True ) 
  189.                             self.__numdeldirs += 1 
  190.                         except shutil.Error, e: 
  191.                             print e 
  192.                             self.__numdeldfld += 1 
  193.                                  
  194.                 except Exception, e: # of any use ? 
  195.                     print e 
  196.                     continue 
  197.  
  198.  
  199.         # Files & directories only in source directory 
  200.         for f1 in self.__dcmp.left_only: 
  201.             try
  202.                st = os.stat(os.path.join(dir1, f1)) 
  203.             except os.error: 
  204.                 continue 
  205.  
  206.             if stat.S_ISREG(st.st_mode): 
  207.                 if copyfunc: copyfunc(f1, dir1, dir2) 
  208.             elif stat.S_ISDIR(st.st_mode): 
  209.                 fulld1 = os.path.join(dir1, f1) 
  210.                 fulld2 = os.path.join(dir2, f1) 
  211.                  
  212.                 if self.__creatdirs: 
  213.                     try
  214.                         # Copy tree 
  215.                         print 'Copying tree', fulld2 
  216.                         shutil.copytree(fulld1, fulld2) 
  217.                         self.__numnewdirs += 1 
  218.                         print 'Done.' 
  219.                     except shutil.Error, e: 
  220.                         print e 
  221.                         self.__numdirsfld += 1 
  222.                          
  223.                         # jump to next file/dir in loop since this op failed 
  224.                         continue 
  225.  
  226.                 # Call tail recursive 
  227.                 # if os.path.exists(fulld2): 
  228.                 #    self.__dowork(fulld1, fulld2, copyfunc, updatefunc) 
  229.  
  230.         # common files/directories 
  231.         for f1 in self.__dcmp.common: 
  232.             try
  233.                 st = os.stat(os.path.join(dir1, f1)) 
  234.             except os.error: 
  235.                 continue 
  236.  
  237.             if stat.S_ISREG(st.st_mode): 
  238.                 if updatefunc: updatefunc(f1, dir1, dir2) 
  239.             elif stat.S_ISDIR(st.st_mode): 
  240.                 fulld1 = os.path.join(dir1, f1) 
  241.                 fulld2 = os.path.join(dir2, f1) 
  242.                 # Call tail recursive 
  243.                 self.__dowork(fulld1, fulld2, copyfunc, updatefunc) 
  244.                  
  245.  
  246.     def __copy(self, filename, dir1, dir2): 
  247.         """ Private function for copying a file """ 
  248.  
  249.         # NOTE: dir1 is source & dir2 is target 
  250.         if self.__copyfiles: 
  251.  
  252.             print 'Copying file', filename, dir1, dir2 
  253.             try
  254.                 if self.__copydirection== 0 or self.__copydirection == 2:  # source to target 
  255.                      
  256.                     if not os.path.exists(dir2): 
  257.                         if self.__forcecopy: 
  258.                             os.chmod(os.path.dirname(dir2), 0777
  259.                         try
  260.                             os.makedirs(dir1) 
  261.                         except OSError, e: 
  262.                             print e 
  263.                             self.__numdirsfld += 1 
  264.                          
  265.                     if self.__forcecopy: 
  266.                         os.chmod(dir2, 0777
  267.  
  268.                     sourcefile = os.path.join(dir1, filename) 
  269.                     try
  270.                         shutil.copy(sourcefile, dir2) 
  271.                         self.__numfiles += 1 
  272.                     except (IOError, OSError), e: 
  273.                         print e 
  274.                         self.__numcopyfld += 1 
  275.                      
  276.                 elif self.__copydirection==1 or self.__copydirection == 2# target to source  
  277.  
  278.                     if not os.path.exists(dir1): 
  279.                         if self.__forcecopy: 
  280.                             os.chmod(os.path.dirname(dir1), 0777
  281.  
  282.                         try
  283.                             os.makedirs(dir1) 
  284.                         except OSError, e: 
  285.                             print e 
  286.                             self.__numdirsfld += 1                           
  287.  
  288.                     targetfile = os.path.abspath(os.path.join(dir1, filename)) 
  289.                     if self.__forcecopy: 
  290.                         os.chmod(dir1, 0777
  291.  
  292.                     sourcefile = os.path.join(dir2, filename) 
  293.                      
  294.                     try
  295.                         shutil.copy(sourcefile, dir1) 
  296.                         self.__numfiles += 1 
  297.                     except (IOError, OSError), e: 
  298.                         print e 
  299.                         self.__numcopyfld += 1 
  300.                      
  301.             except Exception, e: 
  302.                 print 'Error copying  file', filename, e 
  303.  
  304.     def __cmptimestamps(self, filest1, filest2): 
  305.         """ Compare time stamps of two files and return True 
  306.         if file1 (source) is more recent than file2 (target) """ 
  307.  
  308.         return ((filest1.st_mtime > filest2.st_mtime) or \ 
  309.                    (not self.__modtimeonly and (filest1.st_ctime > filest2.st_mtime))) 
  310.      
  311.     def __update(self, filename, dir1, dir2): 
  312.         """ Private function for updating a file based on 
  313.         last time stamp of modification """ 
  314.  
  315.         print 'Updating file', filename 
  316.          
  317.         # NOTE: dir1 is source & dir2 is target         
  318.         if self.__updatefiles: 
  319.  
  320.             file1 = os.path.join(dir1, filename) 
  321.             file2 = os.path.join(dir2, filename) 
  322.  
  323.             try
  324.                 st1 = os.stat(file1) 
  325.                 st2 = os.stat(file2) 
  326.             except os.error: 
  327.                 return -1 
  328.  
  329.             # Update will update in both directions depending 
  330.             # on the timestamp of the file & copy-direction. 
  331.  
  332.             if self.__copydirection==0 or self.__copydirection == 2
  333.  
  334.                 # Update file if file's modification time is older than 
  335.                 # source file's modification time, or creation time. Sometimes 
  336.                 # it so happens that a file's creation time is newer than it's 
  337.                 # modification time! (Seen this on windows) 
  338.                 if self.__cmptimestamps( st1, st2 ): 
  339.                     print 'Updating file ', file2 # source to target 
  340.                     try
  341.                         if self.__forcecopy: 
  342.                             os.chmod(file2, 0666
  343.  
  344.                         try
  345.                             shutil.copy(file1, file2) 
  346.                             self.__numupdates += 1 
  347.                             return 0 
  348.                         except (IOError, OSError), e: 
  349.                             print e 
  350.                             self.__numupdsfld += 1 
  351.                             return -1 
  352.  
  353.                     except Exception, e: 
  354.                         print e 
  355.                         return -1 
  356.  
  357.             elif self.__copydirection==1 or self.__copydirection == 2
  358.  
  359.                 # Update file if file's modification time is older than 
  360.                 # source file's modification time, or creation time. Sometimes 
  361.                 # it so happens that a file's creation time is newer than it's 
  362.                 # modification time! (Seen this on windows) 
  363.                 if self.__cmptimestamps( st2, st1 ): 
  364.                     print 'Updating file ', file1 # target to source 
  365.                     try
  366.                         if self.__forcecopy: 
  367.                             os.chmod(file1, 0666
  368.  
  369.                         try
  370.                             shutil.copy(file2, file1) 
  371.                             self.__numupdates += 1 
  372.                             return 0 
  373.                         except (IOError, OSError), e: 
  374.                             print e 
  375.                             self.__numupdsfld += 1 
  376.                             return -1 
  377.                          
  378.                     except Exception, e: 
  379.                         print e 
  380.                         return -1 
  381.  
  382.         return -1 
  383.  
  384.     def __dirdiffandcopy(self, dir1, dir2): 
  385.         """ Private function which does directory diff & copy """ 
  386.         self.__dowork(dir1, dir2, self.__copy) 
  387.  
  388.     def __dirdiffandupdate(self, dir1, dir2): 
  389.         """ Private function which does directory diff & update  """         
  390.         self.__dowork(dir1, dir2, Noneself.__update) 
  391.  
  392.     def __dirdiffcopyandupdate(self, dir1, dir2): 
  393.         """ Private function which does directory diff, copy and update (synchro) """                
  394.         self.__dowork(dir1, dir2, self.__copy, self.__update) 
  395.  
  396.     def __dirdiff(self): 
  397.         """ Private function which only does directory diff """ 
  398.  
  399.         if self.__dcmp.left_only: 
  400.             print 'Only in'self.__dir1 
  401.             for x in self.__dcmp.left_only: 
  402.                 print '>>', x 
  403.  
  404.         if self.__dcmp.right_only: 
  405.             print 'Only in'self.__dir2 
  406.             for x in self.__dcmp.right_only: 
  407.                 print '<<', x 
  408.  
  409.         if self.__dcmp.common: 
  410.             print 'Common to'self.__dir1,' and ',self.__dir2 
  411.             print 
  412.             for x in self.__dcmp.common: 
  413.                 print '--', x 
  414.         else
  415.             print 'No common files or sub-directories!' 
  416.  
  417.     def synchronize(self): 
  418.         """ Synchronize will try to synchronize two directories w.r.t 
  419.         each other's contents, copying files if necessary from source 
  420.         to target, and creating directories if necessary. If the optional 
  421.         argument purge is True, directories in target (dir2) that are 
  422.         not present in the source (dir1) will be deleted . Synchronization 
  423.         is done in the direction of source to target """ 
  424.  
  425.         self.__copyfiles = True 
  426.         self.__updatefiles = True 
  427.         self.__creatdirs = True 
  428.         self.__copydirection = 0 
  429.  
  430.         print 'Synchronizing directory'self.__dir2, 'with'self.__dir1 ,'\n' 
  431.         self.__dirdiffcopyandupdate(self.__dir1, self.__dir2) 
  432.  
  433.     def update(self): 
  434.         """ Update will try to update the target directory 
  435.         w.r.t source directory. Only files that are common 
  436.         to both directories will be updated, no new files 
  437.         or directories are created """ 
  438.  
  439.         self.__copyfiles = False 
  440.         self.__updatefiles = True 
  441.         self.__purge = False 
  442.         self.__creatdirs = False 
  443.  
  444.         print 'Updating directory'self.__dir2, 'from'self.__dir1 , '\n' 
  445.         self.__dirdiffandupdate(self.__dir1, self.__dir2) 
  446.  
  447.     def dirdiff(self): 
  448.         """ Only report difference in content between two 
  449.         directories """ 
  450.  
  451.         self.__copyfiles = False 
  452.         self.__updatefiles = False 
  453.         self.__purge = False 
  454.         self.__creatdirs = False 
  455.         self.__updatefiles = False 
  456.          
  457.         print 'Difference of directory 'self.__dir2, 'from'self.__dir1 , '\n' 
  458.         self.__dirdiff() 
  459.          
  460.     def report(self): 
  461.         """ Print report of work at the end """ 
  462.  
  463.         # We need only the first 4 significant digits 
  464.         tt = (str(self.__endtime - self.__starttime))[:4
  465.          
  466.         print '\nPython robocopier finished in',tt, 'seconds.' 
  467.         print self.__numdirs, 'directories parsed,',self.__numfiles, 'files copied.' 
  468.         if self.__numdelfiles: 
  469.             print self.__numdelfiles, 'files were purged.' 
  470.         if self.__numdeldirs: 
  471.             print self.__numdeldirs, 'directories were purged.' 
  472.         if self.__numnewdirs: 
  473.             print self.__numnewdirs, 'directories were created.' 
  474.         if self.__numupdates: 
  475.             print self.__numupdates, 'files were updated by timestamp.' 
  476.  
  477.         # Failure stats 
  478.         print '\n' 
  479.         if self.__numcopyfld: 
  480.             print self.__numcopyfld, 'files could not be copied.' 
  481.         if self.__numdirsfld: 
  482.             print self.__numdirsfld, 'directories could not be created.' 
  483.         if self.__numupdsfld: 
  484.             print self.__numupdsfld, 'files could not be updated.' 
  485.         if self.__numdeldfld: 
  486.             print self.__numdeldfld, 'directories could not be purged.' 
  487.         if self.__numdelffld: 
  488.             print self.__numdelffld, 'files could not be purged.' 
  489.          
  490. if __name__=="__main__"
  491.     import sys 
  492.  
  493.     if len(sys.argv)<2
  494.         sys.exit( usage() % PyRobocopier.prog_name ) 
  495.  
  496.     copier = PyRobocopier() 
  497.     copier.parse_args(sys.argv[1:]) 
  498.     copier.do_work() 
  499.  
  500.     # print report at the end 
  501.     copier.report() 

 本文转自阿汐 51CTO博客,原文链接:http://blog.51cto.com/axiii/301212,如需转载请自行联系原作者


相关文章
|
2月前
|
SQL 关系型数据库 数据库
Python SQLAlchemy模块:从入门到实战的数据库操作指南
免费提供Python+PyCharm编程环境,结合SQLAlchemy ORM框架详解数据库开发。涵盖连接配置、模型定义、CRUD操作、事务控制及Alembic迁移工具,以电商订单系统为例,深入讲解高并发场景下的性能优化与最佳实践,助你高效构建数据驱动应用。
302 7
|
2月前
|
监控 安全 程序员
Python日志模块配置:从print到logging的优雅升级指南
从 `print` 到 `logging` 是 Python 开发的必经之路。`print` 调试简单却难维护,日志混乱、无法分级、缺乏上下文;而 `logging` 支持级别控制、多输出、结构化记录,助力项目可维护性升级。本文详解痛点、优势、迁移方案与最佳实践,助你构建专业日志系统,让程序“有记忆”。
227 0
|
3月前
|
数据可视化 Linux iOS开发
Python脚本转EXE文件实战指南:从原理到操作全解析
本教程详解如何将Python脚本打包为EXE文件,涵盖PyInstaller、auto-py-to-exe和cx_Freeze三种工具,包含实战案例与常见问题解决方案,助你轻松发布独立运行的Python程序。
1011 2
|
2月前
|
JSON 算法 API
Python中的json模块:从基础到进阶的实用指南
本文深入解析Python内置json模块的使用,涵盖序列化与反序列化核心函数、参数配置、中文处理、自定义对象转换及异常处理,并介绍性能优化与第三方库扩展,助你高效实现JSON数据交互。(238字)
353 4
|
2月前
|
监控 机器人 编译器
如何将python代码打包成exe文件---PyInstaller打包之神
PyInstaller可将Python程序打包为独立可执行文件,无需用户安装Python环境。它自动分析代码依赖,整合解释器、库及资源,支持一键生成exe,方便分发。使用pip安装后,通过简单命令即可完成打包,适合各类项目部署。
|
2月前
|
Java 调度 数据库
Python threading模块:多线程编程的实战指南
本文深入讲解Python多线程编程,涵盖threading模块的核心用法:线程创建、生命周期、同步机制(锁、信号量、条件变量)、线程通信(队列)、守护线程与线程池应用。结合实战案例,如多线程下载器,帮助开发者提升程序并发性能,适用于I/O密集型任务处理。
260 0
|
2月前
|
XML JSON 数据处理
超越JSON:Python结构化数据处理模块全解析
本文深入解析Python中12个核心数据处理模块,涵盖csv、pandas、pickle、shelve、struct、configparser、xml、numpy、array、sqlite3和msgpack,覆盖表格处理、序列化、配置管理、科学计算等六大场景,结合真实案例与决策树,助你高效应对各类数据挑战。(238字)
177 0
|
3月前
|
安全 大数据 程序员
Python operator模块的methodcaller:一行代码搞定对象方法调用的黑科技
`operator.methodcaller`是Python中处理对象方法调用的高效工具,替代冗长Lambda,提升代码可读性与性能。适用于数据过滤、排序、转换等场景,支持参数传递与链式调用,是函数式编程的隐藏利器。
121 4
|
3月前
|
存储 数据库 开发者
Python SQLite模块:轻量级数据库的实战指南
本文深入讲解Python内置sqlite3模块的实战应用,涵盖数据库连接、CRUD操作、事务管理、性能优化及高级特性,结合完整案例,助你快速掌握SQLite在小型项目中的高效使用,是Python开发者必备的轻量级数据库指南。
284 0
|
4月前
|
缓存 数据可视化 Linux
Python文件/目录比较实战:排除特定类型的实用技巧
本文通过四个实战案例,详解如何使用Python比较目录差异并灵活排除特定文件,涵盖基础比较、大文件处理、跨平台适配与可视化报告生成,助力开发者高效完成目录同步与数据校验任务。
159 0

推荐镜像

更多