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

运行该程序需要安装wxPython。

界面图

源代码:

UNIQFile-wxPython.py

 # -*- coding: gbk -*-

 '''
Author:@DoNotSpyOnMe
Blog: http://www.cnblogs.com/aaronhoo
''' import wx
import hashlib
import os
import threading class WorkerThread(threading.Thread):
def __init__(self, frame,dir,operation,msg):
"""初始化工作线程: 把主窗口传进来"""
threading.Thread.__init__(self)
self.frame = frame
self.dir=dir
self.operation=operation
self.msg=msg
self.setDaemon(True)#设置子线程随UI主线程结束而结束
self.start() #----------------------------------------------------------------------
def run(self):
"""执行工作线程"""
self.frame.SetButtons('operating')
try:
if self.operation=='list':
self.listSameFile(self.dir)
self.frame.btnList.Enable()
elif self.operation=='remove':
self.removeSameFile(self.dir)
self.frame.btnRemove.Enable()
except:
pass
finally:
self.frame.SetButtons('completed')
#
# def stop(self):
# self.keepRunning=False
def appendMsg(self,msg):
if self.frame:
#以下方式可以实现终端式的刷新:自动滚动到最新行
self.frame.txtContent.AppendText(msg+'\n')
#废弃的方式
# currentMsg=self.frame.txtContent.GetValue()
# currentMsg=currentMsg+'\n'+msg
# self.frame.txtContent.SetValue(currentMsg) def getFileSize(self,filePath):
return os.path.getsize(filePath) ''' 一般文件的md5计算方法,一次读取文件的全部内容'''
def CalcMD5(self,filepath):
with open(filepath,'rb') as f:
md5obj = hashlib.md5()
md5obj.update(f.read())
hash = md5obj.hexdigest()
return hash
'''大文件计算md5的方法,分批读取文件内容,防止内存爆掉'''
def GetFileMd5(self,filename):
if not os.path.isfile(filename):
return
myhash = hashlib.md5()
f = open(filename,'rb')
while True:
b = f.read(8*1024)
if not b :
break
myhash.update(b)
f.close()
return myhash.hexdigest() def GetAllFiles(self,directory):
files=[]
for dirpath, dirnames,filenames in os.walk(directory):
if filenames!=[]:
for file in filenames:
files.append(dirpath+'\\'+file)
       files.sort(key=len)#按照文件名的长度排序 
return files def findSameSizeFiles(self,files):
dicSize={}
for f in files:
size=self.getFileSize(f)
if not dicSize.has_key(size):
dicSize[size]=f
else:
dicSize[size]=dicSize[size]+';'+f
dicCopy=dicSize.copy()
for k in dicSize.iterkeys():
if dicSize[k].find(';')==-1:
dicCopy.pop(k)
del dicSize
return dicCopy def findSameMD5Files(self,files):
dicMD5={}
for f in files:
self.appendMsg('calculating the md5 value of file %s'%f)
md5=self.GetFileMd5(f)
if not dicMD5.has_key(md5):
dicMD5[md5]=f
else:
dicMD5[md5]=dicMD5[md5]+';'+f
dicCopy=dicMD5.copy()
for k in dicMD5.iterkeys():
if dicMD5[k].find(';')==-1:
dicCopy.pop(k)
del dicMD5
return dicCopy def removeSameFile(self,mydir):
msg=''
msgUniq='Congratulations,no file is removed since they are all uniq.'
try:
existsFlag=False
files=self.GetAllFiles(mydir)
self.appendMsg('%s files found in directory %s\n'%(len(files),mydir))
dicFileOfSameSize=self.findSameSizeFiles(files)
if dicFileOfSameSize=={}:
self.appendMsg(msgUniq)
return
else:
#list the duplicated files first:
dicFiltered={}
for k in dicFileOfSameSize.iterkeys():
filesOfSameSize=dicFileOfSameSize[k].split(';')
dicSameMD5file=self.findSameMD5Files(filesOfSameSize)
if dicSameMD5file!={}:
existsFlag=True
for k in dicSameMD5file.iterkeys():
msg=msg+'md5 %s: %s'%(k,dicSameMD5file[k])+'\n'
dicFiltered[k]=dicSameMD5file[k]
if not existsFlag:
msg=msgUniq
return
else:
msg='Duplicated files:\n'+msg+'\n'
#then remove the duplicated files:
removeCount=0
for k in dicFiltered.iterkeys():
sameFiles=dicFiltered[k].split(';')
flagRemove=False
for f in sameFiles:
if not flagRemove:
flagRemove=True
else:
msg=msg+'Removing file: %s'%f+'\n'
os.remove(f)
removeCount=removeCount+1
msg=msg+'%s files are removed.\n'%removeCount
except Exception,e:
# print e
msg='Exception occured.'
finally:
self.appendMsg(msg+'\n'+'Operation finished.') def listSameFile(self,mydir):
msg=''
msgUniq='Congratulations,all files are uniq.'
try:
existsFlag=False
files=self.GetAllFiles(mydir)
self.appendMsg('%s files found in directory %s\n'%(len(files),mydir))
dicFileOfSameSize=self.findSameSizeFiles(files)
if dicFileOfSameSize=={}:
self.appendMsg(msgUniq)
return
else:
for k in dicFileOfSameSize.iterkeys():
filesOfSameSize=dicFileOfSameSize[k].split(';')
dicSameMD5file=self.findSameMD5Files(filesOfSameSize)
if dicSameMD5file!={}:
existsFlag=True
for k in dicSameMD5file.iterkeys():
msg=msg+'md5 %s: %s'%(k,dicSameMD5file[k])+'\n'
if not existsFlag:
msg=msgUniq
else:
msg='Duplicated files:\n'+msg
except Exception,e:
# print e
msg='Exception occured.'
finally:
self.appendMsg(msg+'\n'+'Operation finished.') class MyFrame(wx.Frame):
def __init__(self):
super(MyFrame,self).__init__(None,title='UNIQ File-wxPython',size=(780,450))
pan=wx.Panel(self)
self.lblDir=wx.StaticText(pan,-1,'Dir:',style=wx.ALIGN_LEFT)
self.txtFile=wx.TextCtrl(pan,size=(380,30))
# self.txtFile.Disable()
self.btnOpen=wx.Button(pan,label='Pick Directory')
self.btnOpen.Bind(wx.EVT_BUTTON, self.BtnOpenHandler)
self.btnList=wx.Button(pan,label='Find Same')
self.btnList.Bind(wx.EVT_BUTTON, self.BtnListHandler)
self.btnRemove=wx.Button(pan,label='Remove duplicated')
self.btnRemove.Bind(wx.EVT_BUTTON, self.BtnRemoveHandler)
# self.btnStop=wx.Button(pan,label='Stop')
# self.btnStop.Bind(wx.EVT_BUTTON, self.BtnStopHandler) hbox=wx.BoxSizer()
hbox.Add(self.lblDir,proportion=0,flag=wx.LEFT,border=5)
hbox.Add(self.txtFile,proportion=0,flag=wx.LEFT,border=5)
hbox.Add(self.btnOpen,proportion=0,flag=wx.LEFT,border=5)
hbox.Add(self.btnList,proportion=0,flag=wx.LEFT,border=5)
hbox.Add(self.btnRemove,proportion=0,flag=wx.LEFT,border=5)
# hbox.Add(self.btnStop,proportion=0,flag=wx.LEFT,border=5) self.txtContent=wx.TextCtrl(pan,style=wx.TE_MULTILINE|wx.HSCROLL)
vbox=wx.BoxSizer(wx.VERTICAL)
vbox.Add(hbox,proportion=0,flag=wx.EXPAND|wx.ALL,border=5)
vbox.Add(self.txtContent,proportion=1,flag=wx.EXPAND,border=5)
pan.SetSizer(vbox)
# self.SetButtons('init') def BtnOpenHandler(self,event):
dlg = wx.DirDialog(None,u"选择文件夹",style=wx.DD_DEFAULT_STYLE)
if dlg.ShowModal() == wx.ID_OK:
dlg.Destroy()
if dlg.GetPath():
self.dirSelected=dlg.GetPath() #文件夹路径
self.txtFile.SetValue(self.dirSelected) self.SetButtons('selected')
self.txtContent.SetValue('Selected dirctory: %s\n'%self.dirSelected) def BtnListHandler(self,event):
if not self.txtFile.GetValue() or not os.path.isdir(self.txtFile.GetValue()):
wx.MessageBox('please select a valid directory first.','Tip Message',wx.YES_DEFAULT|wx.ICON_INFORMATION)
return
self.dirSelected=self.txtFile.GetValue()
self.txtContent.SetValue('')
msg='Listing same files in %s\n'%self.dirSelected
self.txtContent.SetValue(msg)
workThread=WorkerThread(self,self.dirSelected,'list',msg) def BtnRemoveHandler(self,event):
if not self.txtFile.GetValue() or not os.path.isdir(self.txtFile.GetValue()):
wx.MessageBox('please select a valid directory first.','Tip Message',wx.YES_DEFAULT|wx.ICON_INFORMATION)
return
self.dirSelected=self.txtFile.GetValue()
self.txtContent.SetValue('')
msg='Removing duplicated files in %s\n'%self.dirSelected
self.txtContent.SetValue(msg)
WorkerThread(self,self.dirSelected,'remove',msg) def BtnStopHandler(self,event):
pass def SetButtons(self,status):
if status=='init':
self.btnOpen.Enable()
self.btnList.Disable()
self.btnRemove.Disable()
# self.btnStop.Disable()
elif status=='operating':
self.btnOpen.Disable()
self.btnList.Disable()
self.btnRemove.Disable()
# self.btnStop.Enable()
elif status=='completed':
self.btnOpen.Enable()
self.btnList.Enable()
self.btnRemove.Enable()
# self.btnStop.Disable()
elif status=='selected':
self.btnOpen.Enable()
self.btnList.Enable()
self.btnRemove.Enable()
# self.btnStop.Disable() if __name__=="__main__":
app=wx.App()
MyFrame().Show()
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. phpmyadmin查看创建表的SQL语句

    本人菜鸟 发现创建表的SQL语句还不会 直接phpmyadmin解决的 查看见表的语句除了直接到处SQL格式文件 打开查看外 就是执行语句查询 语句:show create table 表名  貌似大 ...

  2. yum管理

    一.yum发展与作用     在linux系统维护中管理员经常遇到软件包的依赖问题,有时无法解决,比如你在安装库文件时常出现报错问题,说依赖其它软件包.由于这个问题一直困绕linux的广大爱好者,开源 ...

  3. php实现发送邮件

    smtp.php: <?php class smtp {     /* Public Variables */     var $smtp_port;     var $time_out;    ...

  4. Yii2 高级版新建一个 Api 应用

    原文地址:http://www.getyii.com/topic/28 先在项目的根目录下复制一份 backend 为 api: cp backend/ api -r 拷贝 api 环境 cp -a ...

  5. MVC下的客户端模板技术

    1.引言 在Web编程中,我们有时经常需要使用Ajax来访问服务端的接口,然后使用这些返回的数据(一般格式都是JSON)来展示客户端的相关信息.例如:在一个商品列表,我们点击某一样的商品,查看该商品的 ...

  6. JS从剪切板里粘贴图片

    功能需求:在网页中,Ctrl+V,把系统剪切板的图片(比如QQ截图)进行粘贴.显示.上传...,提高用户体验. 参考链接:https://ruby-china.org/topics/17266 git ...

  7. java.util.Date和java.sql.Date的区别和相互转化

    java.util.Date是在除了SQL语句的情况下面使用的.java.sql.Date是针对SQL语句使用的,它只包含日期而没有时间部分它 们都有getTime方法返回毫秒数,自然就可以直接构建. ...

  8. android自定义控件(1)-点击实现开关按钮切换

    自定义控件的步骤.用到的主要方法:   1.首先需要定义一个类,继承自View:对于继承View的类,会需要实现至少一个构造方法:实际上这里一共有三个构造方法: public View (Contex ...

  9. [js/jquery]移动端手势拖动,放大,缩小预览图片

    摘要 有这样的需求需要在手机端预览图片的时候,实现图片的手势拖动,放大缩小功能.最终通过touch.js这个插件实现了效果. touch.js Touch.js是移动设备上的手势识别与事件库, 由百度 ...

  10. nyoj 4 ASCII码排序 java

    java输入字符:1.String s=sc.next(); 2.char a=s.charAt(0); 注意:package   java 中提交不能带package java代码: import ...