今天用wxPython做了一个GUI程序,我称之为UNIQ File,实现查找指定目录内的相同文件,主要原理是计算文件的md5值(计算前先找出文件大小相同的文件,然后计算这些文件的md5值,而不是所有文件都计算,大大减少了md5的计算量),加入了多线程功能。

运行该程序需要安装wxPython。

界面图

源代码:

UNIQFile-wxPython.py

  1. # -*- coding: gbk -*-
  2.  
  3. '''
  4. Author:@DoNotSpyOnMe
  5. Blog: http://www.cnblogs.com/aaronhoo
  6. '''
  7.  
  8. import wx
  9. import hashlib
  10. import os
  11. import threading
  12.  
  13. class WorkerThread(threading.Thread):
  14. def __init__(self, frame,dir,operation,msg):
  15. """初始化工作线程: 把主窗口传进来"""
  16. threading.Thread.__init__(self)
  17. self.frame = frame
  18. self.dir=dir
  19. self.operation=operation
  20. self.msg=msg
  21. self.setDaemon(True)#设置子线程随UI主线程结束而结束
  22. self.start()
  23.  
  24. #----------------------------------------------------------------------
  25. def run(self):
  26. """执行工作线程"""
  27. self.frame.SetButtons('operating')
  28. try:
  29. if self.operation=='list':
  30. self.listSameFile(self.dir)
  31. self.frame.btnList.Enable()
  32. elif self.operation=='remove':
  33. self.removeSameFile(self.dir)
  34. self.frame.btnRemove.Enable()
  35. except:
  36. pass
  37. finally:
  38. self.frame.SetButtons('completed')
  39. #
  40. # def stop(self):
  41. # self.keepRunning=False
  42. def appendMsg(self,msg):
  43. if self.frame:
  44. #以下方式可以实现终端式的刷新:自动滚动到最新行
  45. self.frame.txtContent.AppendText(msg+'\n')
  46. #废弃的方式
  47. # currentMsg=self.frame.txtContent.GetValue()
  48. # currentMsg=currentMsg+'\n'+msg
  49. # self.frame.txtContent.SetValue(currentMsg)
  50.  
  51. def getFileSize(self,filePath):
  52. return os.path.getsize(filePath)
  53.  
  54. ''' 一般文件的md5计算方法,一次读取文件的全部内容'''
  55. def CalcMD5(self,filepath):
  56. with open(filepath,'rb') as f:
  57. md5obj = hashlib.md5()
  58. md5obj.update(f.read())
  59. hash = md5obj.hexdigest()
  60. return hash
  61. '''大文件计算md5的方法,分批读取文件内容,防止内存爆掉'''
  62. def GetFileMd5(self,filename):
  63. if not os.path.isfile(filename):
  64. return
  65. myhash = hashlib.md5()
  66. f = open(filename,'rb')
  67. while True:
  68. b = f.read(8*1024)
  69. if not b :
  70. break
  71. myhash.update(b)
  72. f.close()
  73. return myhash.hexdigest()
  74.  
  75. def GetAllFiles(self,directory):
  76. files=[]
  77. for dirpath, dirnames,filenames in os.walk(directory):
  78. if filenames!=[]:
  79. for file in filenames:
  80. files.append(dirpath+'\\'+file)
           files.sort(key=len)#按照文件名的长度排序 
  81. return files
  82.  
  83. def findSameSizeFiles(self,files):
  84. dicSize={}
  85. for f in files:
  86. size=self.getFileSize(f)
  87. if not dicSize.has_key(size):
  88. dicSize[size]=f
  89. else:
  90. dicSize[size]=dicSize[size]+';'+f
  91. dicCopy=dicSize.copy()
  92. for k in dicSize.iterkeys():
  93. if dicSize[k].find(';')==-1:
  94. dicCopy.pop(k)
  95. del dicSize
  96. return dicCopy
  97.  
  98. def findSameMD5Files(self,files):
  99. dicMD5={}
  100. for f in files:
  101. self.appendMsg('calculating the md5 value of file %s'%f)
  102. md5=self.GetFileMd5(f)
  103. if not dicMD5.has_key(md5):
  104. dicMD5[md5]=f
  105. else:
  106. dicMD5[md5]=dicMD5[md5]+';'+f
  107. dicCopy=dicMD5.copy()
  108. for k in dicMD5.iterkeys():
  109. if dicMD5[k].find(';')==-1:
  110. dicCopy.pop(k)
  111. del dicMD5
  112. return dicCopy
  113.  
  114. def removeSameFile(self,mydir):
  115. msg=''
  116. msgUniq='Congratulations,no file is removed since they are all uniq.'
  117. try:
  118. existsFlag=False
  119. files=self.GetAllFiles(mydir)
  120. self.appendMsg('%s files found in directory %s\n'%(len(files),mydir))
  121. dicFileOfSameSize=self.findSameSizeFiles(files)
  122. if dicFileOfSameSize=={}:
  123. self.appendMsg(msgUniq)
  124. return
  125. else:
  126. #list the duplicated files first:
  127. dicFiltered={}
  128. for k in dicFileOfSameSize.iterkeys():
  129. filesOfSameSize=dicFileOfSameSize[k].split(';')
  130. dicSameMD5file=self.findSameMD5Files(filesOfSameSize)
  131. if dicSameMD5file!={}:
  132. existsFlag=True
  133. for k in dicSameMD5file.iterkeys():
  134. msg=msg+'md5 %s: %s'%(k,dicSameMD5file[k])+'\n'
  135. dicFiltered[k]=dicSameMD5file[k]
  136. if not existsFlag:
  137. msg=msgUniq
  138. return
  139. else:
  140. msg='Duplicated files:\n'+msg+'\n'
  141. #then remove the duplicated files:
  142. removeCount=0
  143. for k in dicFiltered.iterkeys():
  144. sameFiles=dicFiltered[k].split(';')
  145. flagRemove=False
  146. for f in sameFiles:
  147. if not flagRemove:
  148. flagRemove=True
  149. else:
  150. msg=msg+'Removing file: %s'%f+'\n'
  151. os.remove(f)
  152. removeCount=removeCount+1
  153. msg=msg+'%s files are removed.\n'%removeCount
  154. except Exception,e:
  155. # print e
  156. msg='Exception occured.'
  157. finally:
  158. self.appendMsg(msg+'\n'+'Operation finished.')
  159.  
  160. def listSameFile(self,mydir):
  161. msg=''
  162. msgUniq='Congratulations,all files are uniq.'
  163. try:
  164. existsFlag=False
  165. files=self.GetAllFiles(mydir)
  166. self.appendMsg('%s files found in directory %s\n'%(len(files),mydir))
  167. dicFileOfSameSize=self.findSameSizeFiles(files)
  168. if dicFileOfSameSize=={}:
  169. self.appendMsg(msgUniq)
  170. return
  171. else:
  172. for k in dicFileOfSameSize.iterkeys():
  173. filesOfSameSize=dicFileOfSameSize[k].split(';')
  174. dicSameMD5file=self.findSameMD5Files(filesOfSameSize)
  175. if dicSameMD5file!={}:
  176. existsFlag=True
  177. for k in dicSameMD5file.iterkeys():
  178. msg=msg+'md5 %s: %s'%(k,dicSameMD5file[k])+'\n'
  179. if not existsFlag:
  180. msg=msgUniq
  181. else:
  182. msg='Duplicated files:\n'+msg
  183. except Exception,e:
  184. # print e
  185. msg='Exception occured.'
  186. finally:
  187. self.appendMsg(msg+'\n'+'Operation finished.')
  188.  
  189. class MyFrame(wx.Frame):
  190. def __init__(self):
  191. super(MyFrame,self).__init__(None,title='UNIQ File-wxPython',size=(780,450))
  192. pan=wx.Panel(self)
  193. self.lblDir=wx.StaticText(pan,-1,'Dir:',style=wx.ALIGN_LEFT)
  194. self.txtFile=wx.TextCtrl(pan,size=(380,30))
  195. # self.txtFile.Disable()
  196. self.btnOpen=wx.Button(pan,label='Pick Directory')
  197. self.btnOpen.Bind(wx.EVT_BUTTON, self.BtnOpenHandler)
  198. self.btnList=wx.Button(pan,label='Find Same')
  199. self.btnList.Bind(wx.EVT_BUTTON, self.BtnListHandler)
  200. self.btnRemove=wx.Button(pan,label='Remove duplicated')
  201. self.btnRemove.Bind(wx.EVT_BUTTON, self.BtnRemoveHandler)
  202. # self.btnStop=wx.Button(pan,label='Stop')
  203. # self.btnStop.Bind(wx.EVT_BUTTON, self.BtnStopHandler)
  204.  
  205. hbox=wx.BoxSizer()
  206. hbox.Add(self.lblDir,proportion=0,flag=wx.LEFT,border=5)
  207. hbox.Add(self.txtFile,proportion=0,flag=wx.LEFT,border=5)
  208. hbox.Add(self.btnOpen,proportion=0,flag=wx.LEFT,border=5)
  209. hbox.Add(self.btnList,proportion=0,flag=wx.LEFT,border=5)
  210. hbox.Add(self.btnRemove,proportion=0,flag=wx.LEFT,border=5)
  211. # hbox.Add(self.btnStop,proportion=0,flag=wx.LEFT,border=5)
  212.  
  213. self.txtContent=wx.TextCtrl(pan,style=wx.TE_MULTILINE|wx.HSCROLL)
  214. vbox=wx.BoxSizer(wx.VERTICAL)
  215. vbox.Add(hbox,proportion=0,flag=wx.EXPAND|wx.ALL,border=5)
  216. vbox.Add(self.txtContent,proportion=1,flag=wx.EXPAND,border=5)
  217. pan.SetSizer(vbox)
  218. # self.SetButtons('init')
  219.  
  220. def BtnOpenHandler(self,event):
  221. dlg = wx.DirDialog(None,u"选择文件夹",style=wx.DD_DEFAULT_STYLE)
  222. if dlg.ShowModal() == wx.ID_OK:
  223. dlg.Destroy()
  224. if dlg.GetPath():
  225. self.dirSelected=dlg.GetPath() #文件夹路径
  226. self.txtFile.SetValue(self.dirSelected)
  227.  
  228. self.SetButtons('selected')
  229. self.txtContent.SetValue('Selected dirctory: %s\n'%self.dirSelected)
  230.  
  231. def BtnListHandler(self,event):
  232. if not self.txtFile.GetValue() or not os.path.isdir(self.txtFile.GetValue()):
  233. wx.MessageBox('please select a valid directory first.','Tip Message',wx.YES_DEFAULT|wx.ICON_INFORMATION)
  234. return
  235. self.dirSelected=self.txtFile.GetValue()
  236. self.txtContent.SetValue('')
  237. msg='Listing same files in %s\n'%self.dirSelected
  238. self.txtContent.SetValue(msg)
  239. workThread=WorkerThread(self,self.dirSelected,'list',msg)
  240.  
  241. def BtnRemoveHandler(self,event):
  242. if not self.txtFile.GetValue() or not os.path.isdir(self.txtFile.GetValue()):
  243. wx.MessageBox('please select a valid directory first.','Tip Message',wx.YES_DEFAULT|wx.ICON_INFORMATION)
  244. return
  245. self.dirSelected=self.txtFile.GetValue()
  246. self.txtContent.SetValue('')
  247. msg='Removing duplicated files in %s\n'%self.dirSelected
  248. self.txtContent.SetValue(msg)
  249. WorkerThread(self,self.dirSelected,'remove',msg)
  250.  
  251. def BtnStopHandler(self,event):
  252. pass
  253.  
  254. def SetButtons(self,status):
  255. if status=='init':
  256. self.btnOpen.Enable()
  257. self.btnList.Disable()
  258. self.btnRemove.Disable()
  259. # self.btnStop.Disable()
  260. elif status=='operating':
  261. self.btnOpen.Disable()
  262. self.btnList.Disable()
  263. self.btnRemove.Disable()
  264. # self.btnStop.Enable()
  265. elif status=='completed':
  266. self.btnOpen.Enable()
  267. self.btnList.Enable()
  268. self.btnRemove.Enable()
  269. # self.btnStop.Disable()
  270. elif status=='selected':
  271. self.btnOpen.Enable()
  272. self.btnList.Enable()
  273. self.btnRemove.Enable()
  274. # self.btnStop.Disable()
  275.  
  276. if __name__=="__main__":
  277. app=wx.App()
  278. MyFrame().Show()
  279. app.MainLoop()

python查找并删除相同文件-UNIQ File-wxPython版本的更多相关文章

  1. python查找并删除相同文件-UNIQ File-script版本

    今天用wxPython做了一个GUI程序,实现查找指定目录内的相同文件,主要原理是计算文件的md5值(计算前先找出文件大小相同的文件,然后计算这些文件的md5值,而不是所有文件都计算,大大减少了md5 ...

  2. python查找并删除相同文件-UNIQ File-wxPython-v6

    相比第一版,新增:菜单,对话框,文件过滤器,操作结果保存,配置功能(自己写了一个读写配置文件的功能),提示语优化,模块分化更合理. 截图: 源代码: UniqFile-wxPython-v6.py: ...

  3. Linux查找并删除重复文件的命令行fdupes工具,dupeGuru图形工具

    查了几十个网页,找到这个接近满意的解决方案http://unix.stackexchange.com/questions/146197/fdupes-delete-files-aft... 不过正则里 ...

  4. Linux系统中查找、删除重复文件,释放磁盘空间。

    在Linux系操作系统中查找并删除重复文件的方法的确有很多,不过这里介绍的是一款非常简单实用的软件FSlint.FSlint是一个重复文件查找工具,可以使用它来清除不必要的重复文件,笔者经常使用它来释 ...

  5. Python小工具--删除svn文件

    有的时候我们需要删除项目下的svn相关文件,但是SVN会在所有的目录下都创建隐藏文件.svn,手工一个个目录查找然后删除显然比较麻烦.所以这里提供了一个Python小工具用于批量删除svn的相关文件: ...

  6. 利用lsof命令查找已经删除的文件来释放磁盘空间

    测试环境一台服务器/目录空间使用率达到97%,但是通过du -sh *发现实际空间没用到那么多,初步怀疑,之前删除的文件,有运行中的进程一直占用,导致空间没有释放,如图通过du -sh *发现共实际使 ...

  7. 在 Linux 中查找和删除重复文件

    原文链接:https://www.linuxprobe.com/linux-FSlint.html FSlint同时具有GUI和CLI模式.因此,对于新手来说,这是一个用户友好的工具.FSlint不仅 ...

  8. fso查找被删除的文件

    <html> <head> </head> <body> 源目录:<input id="txtOld" value=" ...

  9. python 递归删除空文件夹

    Python如何递归删除空文件夹 1.Python如何递归删除空文件夹,这个问题很常见.但大多数人的解决办法都是自己实现递归函数解决这个问题,其实根本不用那么麻烦.Python中的os.walk提供了 ...

随机推荐

  1. php Hash Table(一) Hash Table的结构

    关于Hash Table专题: 一直想深入理解一下php的hash table的实现,以前一直是星星点点的看看,从未彻底的总结过,那就从这个专题开始吧! 主要想总结几个部分:hashtable结构,h ...

  2. 硬盘安装win10

    http://hd.ruanmei.com/

  3. 免 sudo 使用 docker

    免 sudo 使用 docker 如果还没有 docker group 就添加一个: sudo groupadd docker 将用户加入该 group 内.然后退出并重新登录就生效啦. sudo g ...

  4. sublime设置

    修改字体: "font_face": "Monaco", "font_size": 14.0

  5. javascript取一周的日期

    上代码: <script> var today = new Date(); for (var i = 0; i < 7; i++) { today.setDate(today.get ...

  6. 自动去除nil的NSDictionary和NSArray构造方法

    http://www.jianshu.com/p/a1e8d8d579c7 极分享 http://www.finalshares.com/

  7. nyoj 14 会场安排问题(贪心专题)java

    会场安排问题 时间限制:3000 ms  |  内存限制:65535 KB 难度:4   描述 学校的小礼堂每天都会有许多活动,有时间这些活动的计划时间会发生冲突,需要选择出一些活动进行举办.小刘的工 ...

  8. asp.net—缓存

    1.页面缓存 要实现页面输出缓存,只要将一条 OutputCache 指令添加到页面即可. <%@ OutputCache CacheProfile=" " NoStore= ...

  9. Hanoi问题

    #include<stdio.h>int main(){ int m; void hanoi(int n,char x,char y,char z); printf("input ...

  10. Jetty安装

    下载jetty http://www.eclipse.org/jetty/  看好jdk 版本 安装 解压压缩包到指定目录,且将其目录路径定义为${JETTY_HOME} 进入${JETTY_HOME ...