经常备份手机的照片到PC,如果使用Sync类同步软件备份不存在文件多次备份问题,如果只是复制文件到PC,难免有很多文件会多次备份,要整理一下也得花点时间。就想到开发一个查找重复文件的工具,定期扫描一下备份文件夹,删除重复文件。
整个工具的开发思路比较简单,遍历目录,使用SQLite数据库存储每个文件路径及MD5值, 新文件首先计算MD5值,查找数据库是否存在相同MD5值的文件,如果存在就认位是重复文件,将相关文件信息显示。如果不存在重复文件,就将文件路径信息及MD5值加入数据库。
扫描完成后,根据用户选择可以删除选中文件。
整体界面设计如上图所示,比较简单。这个应用中有几个重点
- 数据库的使用
- 文件列表是通过QTableWidget实现的,文件路径列实现了一个自定义控件
- QTabelWidget中插入控件,获取控件信息的方法
针对上面几个重点直接上代码
- 数据库操作,此处主要是内存数据库的命名方法
#解决再次打开时提示错误
if QSqlDatabase.contains('qt_sql_default_connection'):
QSqlDatabase.removeDatabase('qt_sql_default_connection')
#链接数据库,并打开
self.db = QSqlDatabase.addDatabase('QSQLITE')
self.db.setDatabaseName(':memory:')
if not self.db.open():
QMessageBox.warning(None, "提醒", "数据打开失败,程序退出!")
sys.exit(1)
数据库,查询、插入
#创建表
query = QSqlQuery()
query.exec_("""CREATE TABLE fileInfo (
id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL,
path VARCHAR(255) NOT NULL,
md5 VARCHAR(32) NOT NULL)
""")
#使用MD5算法查重处理
for file in self.list_all_files(self.rootdir):
md5 = self.get_file_md5(file)
#print("%s %s" % (file, md5))
query.exec_("SELECT id, path FROM fileInfo WHERE md5 = '%s'" % md5)
if query.next():
path = query.value(1)
#print(path)
self.signalMsg.emit(['DUPINFO', [path, file]])
else:
#不重复文件信息写入数据库
query.prepare("INSERT INTO fileInfo (path, md5) VALUES(:path, :md5)")
query.bindValue(':path', file)
query.bindValue(':md5', md5)
query.exec_()
2.自定义了一个控件,用来显示两个重复文件的信息
#!/usr/bin/env python
#-*- encoding=utf-8 -*-
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class DupWidgets(QWidget):
def __init__(self, para:list, parent=None):
super(DupWidgets, self).__init__(parent)
self.param = para
self.setupUI()
#self.show()
def setupUI(self):
self.file1Ckbox = QCheckBox()
self.file1Ckbox.setChecked(False)
self.file1Ckbox.setText('%s' % self.param[0])
self.file2Ckbox = QCheckBox()
self.file2Ckbox.setChecked(True)
self.file2Ckbox.setText('%s' % self.param[1])
layout = QVBoxLayout()
layout.addWidget(self.file1Ckbox)
layout.addWidget(self.file2Ckbox)
self.setLayout(layout)
def getCheckedPathInfo(self):
path = []
if self.file1Ckbox.isChecked():
path.append(self.file1Ckbox.text())
if self.file2Ckbox.isChecked():
path.append(self.file2Ckbox.text())
return path
3.QTableWidget中添加控件,及控件信息获取的方法
def tableAddItem(self, infoPara:list):
self.dupFilesCnt = 1
if self.dupFilesCnt > self.tableWidget.rowCount():
self.tableWidget.setRowCount(self.tableWidget.rowCount() 1)
row = self.dupFilesCnt - 1
self.tableWidget.setItem(row, 0, QTableWidgetItem("%d"% self.dupFilesCnt))
item = DupWidgets(('%s' % infoPara[0], '%s' % infoPara[1]))
self.tableWidget.setCellWidget(row, 1, item)
def tableGetSelectFile(self):
for row in range(self.dupFilesCnt):
fileList = self.tableWidget.cellWidget(row, 1).getCheckedPathInfo()
yield fileList
这里获取选中文件列表的函数中,首先获取了表格中插入的自定义控件,并调用控件的成员函数返回当前选中文件路径列表。
到此为止,这个小工具主要代码如上所示,记录以备忘。
,