前言
这个程序陆陆续续开发了几天,正好我在学Python,就一边做一边学,倒是学到不少东西。
不得不说python是快速开发的好工具。
程序做了一些改进,这两天又忙着毕设,现在才想起来发到博客上。想想回头github也要启用起来,不能继续荒废了……
如果嫌运行python程序不方便的话,可以直接使用exe可执行文件版本。
exe发布器在这里:使用pyInstaller发布PathMerge的exe版本(py转换成exe)
废话不多说,我介绍一下这个工具。
应用场景
在日常使用中,我们往往需要把一个文件夹拷到另一个文件夹下面,做一些修改之后,再将改动的文件夹合并回去。
例如,从优盘中把一个要用的文件夹拷到电脑上,在pc机上工作,之后你需要将修改后的文件夹再拷回优盘中带走。
这个时候问题来了。
如果你做的修改不多,我们可以简单的把修改的文件复制回去,这个时候你清楚的记得你到底修改了哪些文件。
但是如果你对很多文件做了改动,并且还创建了几个文件或者文件夹,导致目录结构变得十分复杂,最后你自己都记不起来到底哪些文件做了哪些改动,目录做了哪些更新,这个时候你要把文件夹合并回去就有些凌乱了……
So,你需要一个工具去帮你记忆你做的改动,自动的帮你合并文件夹,并且不会丢失任何文件。
这个时候这个小工具就可以派上用场了~
下面演示一下怎么用。
使用演示
现在有两个工作空间
工作空间1是你之前做好的一个工程或者文件夹,里面放满了文件,目录结构复杂。
详细目录:
工作空间2是你现在要工作的目录,现在是空的。
我们把要用的文件夹拷过来
并在里面做一些改动。
这里不放图了,总之我创建了一个文件夹,创建了两个文件,修改了三个文件……现在目录结构变成这样:
大家看到,1/下多了一个文件夹33,里面多了两个文件111.txt和222.txt,我还修改了一个txt文件,一个ppt文件和一个word文件。
下面运行PathMerge:
输入A目录(修改的文件夹)和B目录(原文件夹),要将A==>B,A合并到B。
回车开始合并:
合并成功!
合并的记录都列在上面了,如果名称相同的文件会将旧文件创建一个副本,修改后的文件直接复制过去,程序中没有删除文件的代码,可放心食用。
上图可知复制了三个文件,创建了三个旧文件副本,另外复制了创建的目录。
将工作空间2中1文件做的所有改动都包含了进去。
以上,就是PathMerge的使用演示。
代码
1 # coding=gbk
2
3 # PathMerge.py
4 # 作者:freecode
5 # 创建时间:2016.4.9 20:15
6 # 作用:
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 '[目录] %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 '[副本] %s ===> %s' %(A_new_path,B_copy_path)
97 shutil.copy2(B_new_path,B_copy_path)
98 # 将A中修改后文件复制过来
99 print '[文件] %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 '[文件] %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
' % (path1)
123 path2 = raw_input('请输入B目录:').strip()
124 elif len(sys.argv) == 3:
125 path1 = sys.argv[1].strip()
126 print 'A目录为:%s
' % (path1)
127 path2 = sys.argv[2].strip()
128 print 'B目录为:%s
' % (path2)
129 else:
130 print 'ERROR:参数错误!
参数最多有三个!
'
131 raw_input('
请按回车键(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 '失败原因:
',e
152 else:
153 print '合并成功!'
154
155 raw_input('
请按回车键(Enter)退出……')
156
工具特性
1、可识别加“”的目录和不加“”的目录。
2、使用MD5识别文件是否修改。
MD5识别文件的内容见上一篇博文:python计算文件的md5值
3、可传递参数,用来写脚本。例:
4、原文件夹内的旧文件不会被删除,而是创建一个带有时间戳的副本。修改过的文件直接复制过去。
这样不用担心合并之后文件莫名其妙的丢失啦。使用该工具不会有文件删除操作。
注意
Sorry,目前仅支持windows环境……
参考资料
原创声明
Freecode# : www.cnblogs.com/yym2013