# 作用:
7 # 合并并兩個目錄/檔案夾。
8 # 将目錄A合并到目錄B,同級目錄下,
9 # 将A中有,B中沒有的目錄完全複制到B中;
10 # 将A中沒有,B中有的目錄不做改動;
11 # 将A中做了修改的檔案,在B的同級目錄下建立一個副本。(注意不是覆寫)
12 #
13 # 适應場景:
14 # 一般A是從B複制過來的檔案夾,做了修改後,想合并回B。
15 # 這樣在A中做的一些改動我們就不知道了,這個程式的作用是,
16 # 将A中修改的部分在B中更新。
17 #
18 # 版本:
19 # 将修改後的檔案完全複制過去
20 # 舊的檔案建立副本
21 # 基于檔案的MD5值判斷是否修改過
22 #
23
24 import os
25 import shutil
26 import time
27 import hashlib
28 import sys
29
30 def Help(): # 輸出幫助文檔
31 print """
32 PathMerge.py
33 作者:freecode
34 建立時間:2016.4.9 20:15
35 作用:
36 合并并兩個目錄/檔案夾。
37 将目錄A合并到目錄B,同級目錄下,
38 将A中有,B中沒有的目錄完全複制到B中;
39 将A中沒有,B中有的目錄不做改動;
40 将A中做了修改的檔案,在B的同級目錄下建立一個副本。(注意不是覆寫)
41
42 适應場景:
43 一般A是從B複制過來的檔案夾,做了修改後,想合并回B。
44 這樣在A中做的一些改動我們就不知道了,這個程式的作用是,
45 将A中修改的部分在B中更新。
46
47 版本:
48 将修改後的檔案完全複制過去
49 舊的檔案建立副本
50 基于檔案的MD5值判斷是否修改過
51 """
52
53 def GetFileMd5(filename): # 計算檔案的md5值
54 if not os.path.isfile(filename):
55 return
56 myhash = hashlib.md5()
57 f = file(filename,'rb')
58 while True:
59 b = f.read(8096)
60 if not b :
61 break
62 myhash.update(b)
63 f.close()
64 return myhash.hexdigest()
65
66 def isModify(A_file,B_file): # 判斷兩個檔案是否相同,如果不同,表示修改過
67 # 參數需是絕對路徑
68 return GetFileMd5(A_file) != GetFileMd5(B_file)
69
70 def Stamp2Time(Stamp): # 将時間戳轉換成時間顯示格式
71 timeArray = time.localtime(Stamp)
72 Time = time.strftime("%Y年%m月%d日 %H時%M分%S秒 舊檔案副本", timeArray)
73 return Time
74
75 def Merge(A_path,B_path): # 合并兩個目錄
76 B_paths = os.listdir(B_path) # 擷取目前B中的目錄結構
77 for fp in os.listdir(A_path): # 周遊目前A目錄中的檔案或檔案夾
78 A_new_path = os.path.join(A_path,fp) # A中的檔案或目錄
79 B_new_path = os.path.join(B_path,fp) # B中對應的檔案或路徑,不一定存在
80
81 if os.path.isdir(A_new_path): # A中的目錄
82 if os.path.exists(B_new_path): # 如果在B中存在
83 Merge(A_new_path,B_new_path) # 繼續合并下一級目錄
84 else: # 如果在B中不存在
85 print '[目錄]\t%s ===> %s' %(A_new_path,B_new_path)
86 shutil.copytree(A_new_path,B_new_path) # 完全複制目錄到B
87
88 elif os.path.isfile(A_new_path): # A中的檔案
89 if os.path.exists(B_new_path): # 如果在B中存在
90 s = os.stat(B_new_path)
91 if isModify(A_new_path,B_new_path) == True: # 如果該檔案修改過
92 # 建立副本
93 suffix = B_new_path.split('.')[-1] # 得到檔案的字尾名
94 # 将B中原檔案建立副本
95 B_copy_path = B_new_path[:-len(suffix)-1]+"(%s)."%(Stamp2Time(s.st_mtime))+suffix
96 print '[副本]\t%s ===> %s' %(A_new_path,B_copy_path)
97 shutil.copy2(B_new_path,B_copy_path)
98 # 将A中修改後檔案複制過來
99 print '[檔案]\t%s ===> %s' %(A_new_path,B_new_path)
100 shutil.copy2(A_new_path,B_new_path)
101 else: # 如果該檔案沒有修改過
102 pass # 不複制
103
104 else: # 如果在B中不存在
105 # 将該檔案複制過去
106 print '[檔案]\t%s ===> %s' %(A_new_path,B_new_path)
107 shutil.copy2(A_new_path,B_new_path)
108
109 # 運作模式
110 if __name__=='__main__':
111 print """
112 歡迎使用PathMerge!
113 本程式将會把目錄A合并到目錄B,即 A ===> B
114 将A目錄中修改的内容在B目錄中更新
115 合并規則具體見 PathMerge.Help()
116 """
117 if len(sys.argv) == 1:
118 path1 = raw_input('請輸入A目錄:').strip()
119 path2 = raw_input('請輸入B目錄:').strip()
120 elif len(sys.argv) == 2:
121 path1 = sys.argv[1].strip()
122 print 'A目錄為:%s\n' % (path1)
123 path2 = raw_input('請輸入B目錄:').strip()
124 elif len(sys.argv) == 3:
125 path1 = sys.argv[1].strip()
126 print 'A目錄為:%s\n' % (path1)
127 path2 = sys.argv[2].strip()
128 print 'B目錄為:%s\n' % (path2)
129 else:
130 print 'ERROR:參數錯誤!\n參數最多有三個!\n'
131 raw_input('\n請按Enter鍵(Enter)退出……')
132 sys.exit(0)
133 # 去除目錄的引号
134 if path1[0]=='\"':
135 path1 = path1[1:-1]
136 if path2[0]=='\"':
137 path2 = path2[1:-1]
138
139 print """
140 開始合并目錄 %s
141 到目錄 %s
142 %s ===> %s
143 """ %(path1,path2,path1,path2)
144
145 try:
146 print '合并中……'
147 Merge(path1,path2)
148 print ''
149 except Exception,e:
150 print '合并失敗!'
151 print '失敗原因:\n',e
152 else:
153 print '合并成功!'
154
155 raw_input('\n請按Enter鍵(Enter)退出……')
156