前言
比如浏览文件夹、导出文件列表、整理特定类型的文件以及比对文本文件内容。本文将详细分析一个基于wxpython开发的文件管理工具,该工具提供了多种实用功能,代码结构清晰,易于理解和扩展。通过学习这个示例,你将掌握如何使用wxpython构建图形界面应用程序和实现常见的文件操作。
全部代码
import wx import os import shutil import datetime import difflib class filemanagerframe(wx.frame): def __init__(self, parent, title): super(filemanagerframe, self).__init__(parent, title=title, size=(800, 600)) # 创建面板和工具栏 self.panel = wx.panel(self) self.toolbar = self.createtoolbar() # 添加工具栏按钮 browse_tool = self.toolbar.addtool(wx.id_any, "浏览", wx.artprovider.getbitmap(wx.art_folder_open), "浏览文件夹") export_tool = self.toolbar.addtool(wx.id_any, "导出", wx.artprovider.getbitmap(wx.art_file_save), "导出结果") organize_tool = self.toolbar.addtool(wx.id_any, "整理", wx.artprovider.getbitmap(wx.art_redo), "整理快捷方式") compare_tool = self.toolbar.addtool(wx.id_any, "比对", wx.artprovider.getbitmap(wx.art_list_view), "比对txt文件") # 实现工具栏 self.toolbar.realize() # 绑定工具栏事件 self.bind(wx.evt_tool, self.onbrowse, browse_tool) self.bind(wx.evt_tool, self.onexport, export_tool) self.bind(wx.evt_tool, self.onorganize, organize_tool) self.bind(wx.evt_tool, self.oncompare, compare_tool) # 创建状态栏 self.statusbar = self.createstatusbar() self.statusbar.setstatustext("准备就绪") # 创建主布局 main_sizer = wx.boxsizer(wx.vertical) # 显示当前路径的文本框 self.path_text = wx.textctrl(self.panel, style=wx.te_readonly) main_sizer.add(self.path_text, 0, wx.expand | wx.all, 5) # 创建列表框用于显示文件 self.listbox = wx.listbox(self.panel, style=wx.lb_single) main_sizer.add(self.listbox, 1, wx.expand | wx.all, 5) # 设置布局 self.panel.setsizerandfit(main_sizer) # 当前选择的目录 self.current_directory = "" # 文件列表 self.file_list = [] # 居中显示窗口 self.center() self.show() def onbrowse(self, event): """浏览按钮处理函数""" # 打开目录选择对话框 dlg = wx.dirdialog(self, "选择要浏览的文件夹", style=wx.dd_default_style) if dlg.showmodal() == wx.id_ok: self.current_directory = dlg.getpath() self.path_text.setvalue(self.current_directory) # 清空列表 self.listbox.clear() self.file_list = [] # 开始遍历文件夹 self.statusbar.setstatustext("正在扫描文件夹...") self.traversedirectory(self.current_directory) self.statusbar.setstatustext(f"扫描完成,共找到 {len(self.file_list)} 个文件") dlg.destroy() def traversedirectory(self, directory): """遍历目录,获取所有文件""" try: for root, dirs, files in os.walk(directory): for file in files: file_path = os.path.join(root, file) rel_path = os.path.relpath(file_path, self.current_directory) self.file_list.append(file_path) self.listbox.append(rel_path) except exception as e: wx.messagebox(f"遍历目录时发生错误: {str(e)}", "错误", wx.ok | wx.icon_error) def onexport(self, event): """导出按钮处理函数""" if not self.file_list: wx.messagebox("没有可导出的内容,请先浏览文件夹", "提示", wx.ok | wx.icon_information) return # 打开保存文件对话框 current_time = datetime.datetime.now().strftime("%y%m%d_%h%m%s") default_filename = f"文件列表_{current_time}.txt" dlg = wx.filedialog( self, "导出文件列表", wildcard="文本文件 (*.txt)|*.txt", style=wx.fd_save | wx.fd_overwrite_prompt, defaultfile=default_filename ) if dlg.showmodal() == wx.id_ok: save_path = dlg.getpath() try: with open(save_path, 'w', encoding='utf-8') as f: f.write(f"文件列表 - {self.current_directory}\n") f.write(f"导出时间: {datetime.datetime.now().strftime('%y-%m-%d %h:%m:%s')}\n") f.write("-" * 50 + "\n\n") for file_path in self.file_list: f.write(f"{file_path}\n") self.statusbar.setstatustext(f"成功导出到 {save_path}") wx.messagebox(f"已成功导出文件列表到:\n{save_path}", "导出成功", wx.ok | wx.icon_information) except exception as e: wx.messagebox(f"导出文件时发生错误: {str(e)}", "错误", wx.ok | wx.icon_error) dlg.destroy() def onorganize(self, event): """整理按钮处理函数""" if not self.file_list: wx.messagebox("没有可整理的内容,请先浏览文件夹", "提示", wx.ok | wx.icon_information) return # 创建快捷方式目录 shortcuts_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "shortcuts") if not os.path.exists(shortcuts_dir): try: os.makedirs(shortcuts_dir) except exception as e: wx.messagebox(f"创建快捷方式目录失败: {str(e)}", "错误", wx.ok | wx.icon_error) return # 计数器 moved_count = 0 error_count = 0 # 寻找并移动快捷方式文件 shortcut_extensions = ['.lnk', '.url'] # windows快捷方式扩展名 for file_path in self.file_list[:]: # 使用副本进行遍历 _, ext = os.path.splitext(file_path) if ext.lower() in shortcut_extensions: try: # 获取文件名 file_name = os.path.basename(file_path) # 目标路径 dest_path = os.path.join(shortcuts_dir, file_name) # 如果存在同名文件,添加数字后缀 if os.path.exists(dest_path): name, ext = os.path.splitext(file_name) counter = 1 while os.path.exists(dest_path): dest_path = os.path.join(shortcuts_dir, f"{name}_{counter}{ext}") counter += 1 # 移动文件 shutil.move(file_path, dest_path) # 从列表中移除 self.file_list.remove(file_path) moved_count += 1 except exception as e: error_count += 1 print(f"移动文件时出错: {str(e)}") # 刷新列表显示 self.listbox.clear() for file_path in self.file_list: rel_path = os.path.relpath(file_path, self.current_directory) self.listbox.append(rel_path) # 显示结果 if moved_count > 0: self.statusbar.setstatustext(f"已成功移动 {moved_count} 个快捷方式文件") wx.messagebox( f"整理完成\n成功移动: {moved_count} 个快捷方式文件\n失败: {error_count} 个\n\n快捷方式已移动到:\n{shortcuts_dir}", "整理完成", wx.ok | wx.icon_information ) else: self.statusbar.setstatustext("未找到快捷方式文件") wx.messagebox("未找到快捷方式文件", "提示", wx.ok | wx.icon_information) def oncompare(self, event): """比对文件按钮处理函数""" # 创建文件选择对话框 dlg = wx.filedialog( self, "选择第一个txt文件", wildcard="文本文件 (*.txt)|*.txt", style=wx.fd_open | wx.fd_file_must_exist ) if dlg.showmodal() != wx.id_ok: dlg.destroy() return file1_path = dlg.getpath() dlg.destroy() # 选择第二个文件 dlg = wx.filedialog( self, "选择第二个txt文件", wildcard="文本文件 (*.txt)|*.txt", style=wx.fd_open | wx.fd_file_must_exist ) if dlg.showmodal() != wx.id_ok: dlg.destroy() return file2_path = dlg.getpath() dlg.destroy() # 读取文件内容 try: with open(file1_path, 'r', encoding='utf-8', errors='replace') as f1: content1 = f1.readlines() with open(file2_path, 'r', encoding='utf-8', errors='replace') as f2: content2 = f2.readlines() # 获取文件名用于显示 file1_name = os.path.basename(file1_path) file2_name = os.path.basename(file2_path) # 使用difflib比对文件 diff = list(difflib.unified_diff( content1, content2, fromfile=file1_name, tofile=file2_name, n=3 # 上下文行数 )) # 如果没有差异 if not diff: wx.messagebox(f"文件内容完全相同:\n{file1_name}\n{file2_name}", "比对结果", wx.ok | wx.icon_information) return # 创建比对结果窗口 self.showcompareresults(file1_name, file2_name, diff) except exception as e: wx.messagebox(f"比对文件时发生错误: {str(e)}", "错误", wx.ok | wx.icon_error) def showcompareresults(self, file1_name, file2_name, diff_results): """显示比对结果的对话框""" # 创建对话框 dlg = wx.dialog(self, title=f"文件比对结果: {file1_name} vs {file2_name}", size=(800, 600)) # 创建布局 sizer = wx.boxsizer(wx.vertical) # 标题标签 title_text = wx.statictext(dlg, label=f"文件比对结果") title_text.setfont(wx.font(12, wx.fontfamily_default, wx.fontstyle_normal, wx.fontweight_bold)) sizer.add(title_text, 0, wx.all | wx.center, 10) # 文件信息 info_text = wx.statictext(dlg, label=f"比对文件:\n{file1_name}\n{file2_name}") sizer.add(info_text, 0, wx.all | wx.expand, 10) # 创建文本控件显示比对结果 diff_text = wx.textctrl(dlg, style=wx.te_multiline | wx.te_readonly | wx.hscroll) # 设置等宽字体便于阅读差异 font = wx.font(10, wx.fontfamily_teletype, wx.fontstyle_normal, wx.fontweight_normal) diff_text.setfont(font) # 使用不同颜色显示添加和删除的行 for line in diff_results: if line.startswith('+'): # 跳过文件名行 if not line.startswith('+++ '): diff_text.setdefaultstyle(wx.textattr(wx.colour(0, 128, 0))) # 绿色表示添加 elif line.startswith('-'): # 跳过文件名行 if not line.startswith('--- '): diff_text.setdefaultstyle(wx.textattr(wx.colour(255, 0, 0))) # 红色表示删除 else: diff_text.setdefaultstyle(wx.textattr(wx.colour(0, 0, 0))) # 黑色表示上下文 diff_text.appendtext(line) sizer.add(diff_text, 1, wx.all | wx.expand, 10) # 添加导出按钮 export_btn = wx.button(dlg, label="导出比对结果") sizer.add(export_btn, 0, wx.all | wx.center, 10) # 关闭按钮 close_btn = wx.button(dlg, wx.id_close, "关闭") sizer.add(close_btn, 0, wx.all | wx.center, 10) # 绑定导出按钮事件 export_btn.bind(wx.evt_button, lambda evt, d=diff_results, f1=file1_name, f2=file2_name: self.exportcompareresults(d, f1, f2)) # 绑定关闭按钮事件 close_btn.bind(wx.evt_button, lambda evt: dlg.endmodal(wx.id_close)) # 设置布局 dlg.setsizer(sizer) # 显示对话框 dlg.showmodal() dlg.destroy() def exportcompareresults(self, diff_results, file1_name, file2_name): """导出比对结果""" # 创建保存文件对话框 current_time = datetime.datetime.now().strftime("%y%m%d_%h%m%s") default_filename = f"比对结果_{current_time}.txt" dlg = wx.filedialog( self, "保存比对结果", wildcard="文本文件 (*.txt)|*.txt", style=wx.fd_save | wx.fd_overwrite_prompt, defaultfile=default_filename ) if dlg.showmodal() == wx.id_ok: save_path = dlg.getpath() try: with open(save_path, 'w', encoding='utf-8') as f: f.write(f"文件比对结果\n") f.write(f"比对时间: {datetime.datetime.now().strftime('%y-%m-%d %h:%m:%s')}\n") f.write(f"文件1: {file1_name}\n") f.write(f"文件2: {file2_name}\n") f.write("-" * 50 + "\n\n") for line in diff_results: f.write(line) wx.messagebox(f"比对结果已成功导出到:\n{save_path}", "导出成功", wx.ok | wx.icon_information) except exception as e: wx.messagebox(f"导出比对结果时发生错误: {str(e)}", "错误", wx.ok | wx.icon_error) dlg.destroy() def main(): app = wx.app() frame = filemanagerframe(none, "文件管理工具") app.mainloop() if __name__ == "__main__": main()
一、项目概述
这个文件管理工具具有以下核心功能:
- 浏览文件夹:递归遍历指定文件夹中的所有文件
- 显示文件列表:在列表框中展示文件路径
- 导出文件列表:将文件列表导出为txt文档
- 整理快捷方式:将快捷链接文件(.lnk, .url)移动到指定文件夹
- 比对文本文档:对比两个txt文件的内容差异并显示结果
接下来,我们将从界面设计、功能实现到代码结构等方面进行详细分析。
二、环境准备
在开始之前,确保已安装wxpython库:
pip install wxpython
wxpython是python语言的一套优秀的gui图形库,它是python语言对wxwidgets c++跨平台gui库的封装,提供了丰富的gui控件和功能。
三、界面设计分析
该应用程序采用了简洁而功能齐全的界面设计,主要包括以下元素:
1. 主窗口框架
应用程序使用wx.frame作为主窗口容器,设置了标题和初始大小:
class filemanagerframe(wx.frame): def __init__(self, parent, title): super(filemanagerframe, self).__init__(parent, title=title, size=(800, 600))
2. 工具栏设计
工具栏是应用程序的核心导航元素,包含四个功能按钮,每个按钮都使用了直观的图标:
self.toolbar = self.createtoolbar() browse_tool = self.toolbar.addtool(wx.id_any, "浏览", wx.artprovider.getbitmap(wx.art_folder_open), "浏览文件夹") export_tool = self.toolbar.addtool(wx.id_any, "导出", wx.artprovider.getbitmap(wx.art_file_save), "导出结果") organize_tool = self.toolbar.addtool(wx.id_any, "整理", wx.artprovider.getbitmap(wx.art_redo), "整理快捷方式") compare_tool = self.toolbar.addtool(wx.id_any, "比对", wx.artprovider.getbitmap(wx.art_list_view), "比对txt文件") self.toolbar.realize()
这里使用了wx.artprovider提供的标准图标,这是一个很好的实践,因为它们在不同平台上都能保持一致的外观。
3. 状态栏
状态栏用于显示当前操作的状态信息,提供了良好的用户反馈:
self.statusbar = self.createstatusbar() self.statusbar.setstatustext("准备就绪")
4. 主布局设计
主界面采用垂直的盒子布局(boxsizer),包含路径显示文本框和文件列表框:
main_sizer = wx.boxsizer(wx.vertical) self.path_text = wx.textctrl(self.panel, style=wx.te_readonly) main_sizer.add(self.path_text, 0, wx.expand | wx.all, 5) self.listbox = wx.listbox(self.panel, style=wx.lb_single) main_sizer.add(self.listbox, 1, wx.expand | wx.all, 5)
这里的布局使用了比例设置,文件列表框设置为1,可以随窗口调整大小而自动扩展。
四、核心功能实现分析
1. 文件夹浏览功能
浏览功能通过onbrowse方法实现,使用wx.dirdialog让用户选择文件夹:
def onbrowse(self, event): dlg = wx.dirdialog(self, "选择要浏览的文件夹", style=wx.dd_default_style) if dlg.showmodal() == wx.id_ok: self.current_directory = dlg.getpath() self.path_text.setvalue(self.current_directory) # 清空列表 self.listbox.clear() self.file_list = [] # 开始遍历文件夹 self.statusbar.setstatustext("正在扫描文件夹...") self.traversedirectory(self.current_directory) self.statusbar.setstatustext(f"扫描完成,共找到 {len(self.file_list)} 个文件") dlg.destroy()
文件遍历通过os.walk实现递归遍历,这是python处理文件系统的标准方法:
def traversedirectory(self, directory): try: for root, dirs, files in os.walk(directory): for file in files: file_path = os.path.join(root, file) rel_path = os.path.relpath(file_path, self.current_directory) self.file_list.append(file_path) self.listbox.append(rel_path) except exception as e: wx.messagebox(f"遍历目录时发生错误: {str(e)}", "错误", wx.ok | wx.icon_error)
这里值得注意的是:
- 使用os.path.relpath计算相对路径,使显示更简洁
- 添加了异常处理,增强程序的健壮性
2. 导出文件列表功能
导出功能通过onexport方法实现,使用wx.filedialog让用户选择保存位置:
def onexport(self, event): if not self.file_list: wx.messagebox("没有可导出的内容,请先浏览文件夹", "提示", wx.ok | wx.icon_information) return # 生成默认文件名(包含时间戳) current_time = datetime.datetime.now().strftime("%y%m%d_%h%m%s") default_filename = f"文件列表_{current_time}.txt" dlg = wx.filedialog( self, "导出文件列表", wildcard="文本文件 (*.txt)|*.txt", style=wx.fd_save | wx.fd_overwrite_prompt, defaultfile=default_filename ) if dlg.showmodal() == wx.id_ok: save_path = dlg.getpath() try: with open(save_path, 'w', encoding='utf-8') as f: f.write(f"文件列表 - {self.current_directory}\n") f.write(f"导出时间: {datetime.datetime.now().strftime('%y-%m-%d %h:%m:%s')}\n") f.write("-" * 50 + "\n\n") for file_path in self.file_list: f.write(f"{file_path}\n") self.statusbar.setstatustext(f"成功导出到 {save_path}") wx.messagebox(f"已成功导出文件列表到:\n{save_path}", "导出成功", wx.ok | wx.icon_information) except exception as e: wx.messagebox(f"导出文件时发生错误: {str(e)}", "错误", wx.ok | wx.icon_error) dlg.destroy()
这个功能的亮点:
- 使用时间戳生成默认文件名,避免覆盖
- 添加了文件头信息,包括路径和时间
- 使用wx.fd_overwrite_prompt标志提示用户文件已存在
3. 整理快捷方式功能
整理功能通过onorganize方法实现,将快捷方式文件移动到指定文件夹:
def onorganize(self, event): if not self.file_list: wx.messagebox("没有可整理的内容,请先浏览文件夹", "提示", wx.ok | wx.icon_information) return # 创建快捷方式目录 shortcuts_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "shortcuts") if not os.path.exists(shortcuts_dir): try: os.makedirs(shortcuts_dir) except exception as e: wx.messagebox(f"创建快捷方式目录失败: {str(e)}", "错误", wx.ok | wx.icon_error) return # 计数器和文件移动逻辑 moved_count = 0 error_count = 0 shortcut_extensions = ['.lnk', '.url'] for file_path in self.file_list[:]: # 使用副本进行遍历 _, ext = os.path.splitext(file_path) if ext.lower() in shortcut_extensions: try: # 文件移动逻辑 file_name = os.path.basename(file_path) dest_path = os.path.join(shortcuts_dir, file_name) # 处理同名文件 if os.path.exists(dest_path): name, ext = os.path.splitext(file_name) counter = 1 while os.path.exists(dest_path): dest_path = os.path.join(shortcuts_dir, f"{name}_{counter}{ext}") counter += 1 shutil.move(file_path, dest_path) self.file_list.remove(file_path) moved_count += 1 except exception as e: error_count += 1 print(f"移动文件时出错: {str(e)}") # 刷新列表和显示结果 # ...
这个功能的技术要点:
- 使用列表的副本进行遍历,同时修改原列表
- 处理文件重名情况,通过添加数字后缀解决
- 使用shutil.move进行文件移动操作
4. 文件比对功能
文件比对是本应用的一个亮点功能,通过oncompare方法实现:
def oncompare(self, event): # 选择第一个文件 dlg = wx.filedialog( self, "选择第一个txt文件", wildcard="文本文件 (*.txt)|*.txt", style=wx.fd_open | wx.fd_file_must_exist ) if dlg.showmodal() != wx.id_ok: dlg.destroy() return file1_path = dlg.getpath() dlg.destroy() # 选择第二个文件 # ... # 读取文件内容 try: with open(file1_path, 'r', encoding='utf-8', errors='replace') as f1: content1 = f1.readlines() with open(file2_path, 'r', encoding='utf-8', errors='replace') as f2: content2 = f2.readlines() # 使用difflib比对文件 diff = list(difflib.unified_diff( content1, content2, fromfile=file1_name, tofile=file2_name, n=3 # 上下文行数 )) # 比对结果处理 # ...
比对结果显示通过showcompareresults方法实现,创建一个新对话框:
def showcompareresults(self, file1_name, file2_name, diff_results): # 创建对话框 dlg = wx.dialog(self, title=f"文件比对结果: {file1_name} vs {file2_name}", size=(800, 600)) # 创建布局和控件 # ... # 使用不同颜色显示差异 for line in diff_results: if line.startswith('+'): # 跳过文件名行 if not line.startswith('+++ '): diff_text.setdefaultstyle(wx.textattr(wx.colour(0, 128, 0))) # 绿色表示添加 elif line.startswith('-'): # 跳过文件名行 if not line.startswith('--- '): diff_text.setdefaultstyle(wx.textattr(wx.colour(255, 0, 0))) # 红色表示删除 else: diff_text.setdefaultstyle(wx.textattr(wx.colour(0, 0, 0))) # 黑色表示上下文 diff_text.appendtext(line) # 显示对话框 # ...
文件比对功能的技术亮点:
- 使用python标准库difflib进行文本比对
- 采用统一差异格式(unified diff)显示结果
- 使用颜色区分添加、删除和上下文行,提高可读性
- 提供导出比对结果功能
五、代码架构与设计模式分析
1. 类结构设计
整个应用程序采用了面向对象的设计,主要由filemanagerframe类构成。这个类继承自wx.frame,负责创建主窗口和处理所有事件。这种设计的优点是将界面和功能封装在一起,代码组织清晰。
2. 事件处理机制
该应用采用wxpython的事件驱动模型,通过bind方法将事件与处理函数绑定:
self.bind(wx.evt_tool, self.onbrowse, browse_tool) self.bind(wx.evt_tool, self.onexport, export_tool) self.bind(wx.evt_tool, self.onorganize, organize_tool) self.bind(wx.evt_tool, self.oncompare, compare_tool)
事件处理函数命名采用了on+事件的规范,使代码更易读和维护。
3. 错误处理机制
代码中广泛使用了异常处理机制,提高了程序的健壮性:
try: # 可能出错的代码 except exception as e: wx.messagebox(f"出错信息: {str(e)}", "错误", wx.ok | wx.icon_error)
通过友好的错误提示,提升了用户体验。
4. 状态管理
应用程序维护了当前目录和文件列表两个核心状态变量:
# 当前选择的目录 self.current_directory = "" # 文件列表 self.file_list = []
各个功能模块都基于这些状态变量工作,体现了良好的状态管理设计。
六、代码优化与扩展建议
1. 代码优化点
线程处理:对于大文件夹的遍历,可以考虑使用线程处理,避免界面冻结:
import threading def onbrowse(self, event): # ... # 使用线程处理耗时操作 threading.thread(target=self.traversedirectorythread, args=(self.current_directory,)).start() def traversedirectorythread(self, directory): # 遍历逻辑 # 完成后使用wx.callafter更新ui wx.callafter(self.updatefilelist, file_list)
配置持久化:添加配置保存功能,记住上次操作的路径:
import json def saveconfig(self): config = { 'last_directory': self.current_directory } with open('config.json', 'w') as f: json.dump(config, f) def loadconfig(self): try: with open('config.json', 'r') as f: config = json.load(f) self.current_directory = config.get('last_directory', '') except: pass
文件过滤功能:添加文件过滤选项,只显示特定类型的文件:
def traversedirectory(self, directory, file_filter="*.*"): # 根据filter过滤文件 import fnmatch # ... if fnmatch.fnmatch(file, file_filter): # 添加到列表
2. 可扩展功能
文件预览:添加文本文件内容预览功能
文件搜索:添加按文件名搜索功能
文件操作:增加复制、删除、重命名等基本文件操作
多标签支持:支持同时浏览多个文件夹
拖放支持:支持文件拖放功能
3.运行结果
以上就是基于python wxpython开发文件管理工具的详细内容,更多关于python文件管理的资料请关注代码网其它相关文章!
发表评论