[Python代码]两目录文件对比程序(界面版)
在前一天的文章中,发布了两目录文件对比程序的Python脚本版本,今天发布这个程序的界面版本(PyQt4)。
功能:除前述功能外,还增加了排除文件夹的功能。
输入:选择两个目录路径(必选),以及排除目录列表(可选)。
输出:记录有不同文件的文件名的文本differnent_file.txt,和记录有无法处理的文件的文件名的文本error_file.txt。
以下部分为源代码:
根据窗体自动编译的界面文件(Ui_file_contrast_ui.py):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# -*- coding: utf-8 -*- from PyQt4 import QtCore, QtGui try: _fromUtf8 = QtCore.QString.fromUtf8 except AttributeError: def _fromUtf8(s): return s try: _encoding = QtGui.QApplication.UnicodeUTF8 def _translate(context, text, disambig): return QtGui.QApplication.translate(context, text, disambig, _encoding) except AttributeError: def _translate(context, text, disambig): return QtGui.QApplication.translate(context, text, disambig) class Ui_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName(_fromUtf8("Dialog")) Dialog.resize(400, 400) Dialog.setMinimumSize(QtCore.QSize(400, 400)) Dialog.setMaximumSize(QtCore.QSize(400, 400)) self.btnContrast = QtGui.QPushButton(Dialog) self.btnContrast.setGeometry(QtCore.QRect(10, 340, 381, 51)) self.btnContrast.setObjectName(_fromUtf8("btnContrast")) self.groupBox = QtGui.QGroupBox(Dialog) self.groupBox.setGeometry(QtCore.QRect(10, 20, 381, 101)) self.groupBox.setObjectName(_fromUtf8("groupBox")) self.label_2 = QtGui.QLabel(self.groupBox) self.label_2.setGeometry(QtCore.QRect(20, 62, 54, 12)) self.label_2.setObjectName(_fromUtf8("label_2")) self.btnPathChoose2 = QtGui.QPushButton(self.groupBox) self.btnPathChoose2.setGeometry(QtCore.QRect(320, 58, 40, 25)) self.btnPathChoose2.setFocusPolicy(QtCore.Qt.StrongFocus) self.btnPathChoose2.setObjectName(_fromUtf8("btnPathChoose2")) self.txtPath1 = QtGui.QLineEdit(self.groupBox) self.txtPath1.setGeometry(QtCore.QRect(70, 30, 241, 20)) self.txtPath1.setFocusPolicy(QtCore.Qt.StrongFocus) self.txtPath1.setReadOnly(True) self.txtPath1.setObjectName(_fromUtf8("txtPath1")) self.txtPath2 = QtGui.QLineEdit(self.groupBox) self.txtPath2.setGeometry(QtCore.QRect(70, 60, 241, 20)) self.txtPath2.setFocusPolicy(QtCore.Qt.StrongFocus) self.txtPath2.setReadOnly(True) self.txtPath2.setObjectName(_fromUtf8("txtPath2")) self.btnPathChoose1 = QtGui.QPushButton(self.groupBox) self.btnPathChoose1.setGeometry(QtCore.QRect(320, 28, 40, 25)) self.btnPathChoose1.setFocusPolicy(QtCore.Qt.StrongFocus) self.btnPathChoose1.setObjectName(_fromUtf8("btnPathChoose1")) self.label = QtGui.QLabel(self.groupBox) self.label.setGeometry(QtCore.QRect(20, 32, 54, 12)) self.label.setObjectName(_fromUtf8("label")) self.groupBox_2 = QtGui.QGroupBox(Dialog) self.groupBox_2.setGeometry(QtCore.QRect(10, 140, 381, 181)) self.groupBox_2.setObjectName(_fromUtf8("groupBox_2")) self.btnPathChooseExclude = QtGui.QPushButton(self.groupBox_2) self.btnPathChooseExclude.setGeometry(QtCore.QRect(90, 20, 75, 25)) self.btnPathChooseExclude.setObjectName(_fromUtf8("btnPathChooseExclude")) self.label_3 = QtGui.QLabel(self.groupBox_2) self.label_3.setGeometry(QtCore.QRect(20, 27, 54, 12)) self.label_3.setObjectName(_fromUtf8("label_3")) self.txtPathExclude = QtGui.QTextBrowser(self.groupBox_2) self.txtPathExclude.setGeometry(QtCore.QRect(20, 50, 341, 121)) self.txtPathExclude.setObjectName(_fromUtf8("txtPathExclude")) self.btnClearExcludeList = QtGui.QPushButton(self.groupBox_2) self.btnClearExcludeList.setGeometry(QtCore.QRect(260, 20, 100, 25)) self.btnClearExcludeList.setObjectName(_fromUtf8("btnClearExcludeList")) self.retranslateUi(Dialog) QtCore.QMetaObject.connectSlotsByName(Dialog) def retranslateUi(self, Dialog): Dialog.setWindowTitle(_translate("Dialog", "文件对比程序 by Alioth", None)) self.btnContrast.setText(_translate("Dialog", "开始对比", None)) self.groupBox.setTitle(_translate("Dialog", "选择需要对比的目录", None)) self.label_2.setText(_translate("Dialog", "目录2:", None)) self.btnPathChoose2.setText(_translate("Dialog", "...", None)) self.btnPathChoose1.setText(_translate("Dialog", "...", None)) self.label.setText(_translate("Dialog", "目录1:", None)) self.groupBox_2.setTitle(_translate("Dialog", "选择需要排除的目录", None)) self.btnPathChooseExclude.setText(_translate("Dialog", "...", None)) self.label_3.setText(_translate("Dialog", "排除目录:", None)) self.btnClearExcludeList.setText(_translate("Dialog", "清空排除列表", None)) if __name__ == "__main__": import sys app = QtGui.QApplication(sys.argv) Dialog = QtGui.QDialog() ui = Ui_Dialog() ui.setupUi(Dialog) Dialog.show() sys.exit(app.exec_()) |
自定义槽文件(file_contrast_ui.py):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
# -*- coding: utf-8 -*- import sys import os from PyQt4 import QtGui from PyQt4 import QtCore import file_contrast_core from Ui_file_contrast_ui import Ui_Dialog class FileContrast(QtGui.QDialog, Ui_Dialog): def __init__(self, parent = None): QtGui.QDialog.__init__(self, parent) self.setupUi(self) self.exclude_list = [] @QtCore.pyqtSignature("") def on_btnPathChoose1_clicked(self): path = QtGui.QFileDialog.getExistingDirectory(self, u"选择目录").replace("/", "\\") self.txtPath1.setText(path) @QtCore.pyqtSignature("") def on_btnPathChoose2_clicked(self): path = QtGui.QFileDialog.getExistingDirectory(self, u"选择目录").replace("/", "\\") self.txtPath2.setText(path) @QtCore.pyqtSignature("") def on_btnPathChooseExclude_clicked(self): path = str(QtGui.QFileDialog.getExistingDirectory(self, u"选择目录")).replace("/", "\\") # 只有两目录均选择好时才可以选择排除目录 if self.get_formated_path1() == '' or self.get_formated_path2() == '': return # 去除路径头部;对不在已选目录中的不允许加入 if path.startswith(self.get_formated_path1()): path = path.replace(self.get_formated_path1(), '', 1) elif path.startswith(self.get_formated_path2()): path = path.replace(self.get_formated_path2(), '', 1) elif path != '': path = '' QtGui.QMessageBox.warning(self, u'注意!', u'请选择添加目录中包含的路径!') if path not in self.exclude_list and path != '': self.exclude_list.append(path) old_text = self.txtPathExclude.toPlainText() self.txtPathExclude.setText(old_text + unicode(path) + '\n') @QtCore.pyqtSignature("") def on_btnContrast_clicked(self): different_file, error_file = file_contrast_core.get_contrast_result(self.get_formated_path1(), self.get_formated_path2(), self.exclude_list) file_contrast_core.write_file("different_file.txt", different_file) file_contrast_core.write_file("error_file.txt", error_file) QtGui.QMessageBox.warning(self, u'完成!', u'文件对比完成!\n请查看different_file.txt获取不同文件列表\n请查看error_file.txt获取错误日志') @QtCore.pyqtSignature("") def on_btnClearExcludeList_clicked(self): self.exclude_list = [] self.txtPathExclude.setText('') def get_formated_path1(self): return self.format_path(self.txtPath1.text()) def get_formated_path2(self): return self.format_path(self.txtPath2.text()) def format_path(self, path): return str(path).rstrip('\\') + '\\' if __name__ == "__main__": # 解决编码为ascii的问题 reload(sys) sys.setdefaultencoding('utf-8') app = QtGui.QApplication(sys.argv) dlg = FileContrast() dlg.show() sys.exit(app.exec_()) |
对比程序核心函数文件(file_contrast_core.py):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# -*- coding: utf-8 -*- import os def get_file_info_list(path, exclude_list): file_info_list = {} error_file = [] path = path.decode("utf-8") for root, dir_list, file_list in os.walk(path): for file_name in file_list: cur_file = os.path.join(root, file_name).decode("utf-8") is_exclude = 0 for exclude_dir in exclude_list: if cur_file.startswith(path + exclude_dir): is_exclude = 1 break if is_exclude == 0: # Added try-except to prevent "windows error" causing by filename parsing error try: file_stat = os.stat(cur_file) file_info = { 'file_size': file_stat[-4], 'file_mtime': file_stat[-2], } file_info_list[cur_file.replace(path, '', 1)] = file_info except: error_file.append(cur_file) return file_info_list, error_file def get_contrast_result(path1, path2, exclude_list): '''Warning: the path transfered in should be a string''' file_info_list1, error_file1 = get_file_info_list(path1, exclude_list) file_info_list2, error_file2 = get_file_info_list(path2, exclude_list) for fi in file_info_list1.keys(): if fi in file_info_list2.keys(): if file_info_list1[fi] == file_info_list2[fi]: del file_info_list1[fi] del file_info_list2[fi] different_file = add_root_path(path1, file_info_list1) different_file += add_root_path(path2, file_info_list2) different_file.sort() error_file = error_file1 + error_file2 return different_file, error_file def add_root_path(path, file_info_list): return [os.path.join(path, name) for name in file_info_list.keys()] def write_file(filename, content): with open(filename, "w") as f: f.writelines([line + os.linesep for line in content]) |
本文内容遵从CC3.0版权协议,转载请注明:转自Pythoner
本文链接地址:[Python代码]两目录文件对比程序(界面版)
暂无评论