前言
比如浏览文件夹、导出文件列表、整理特定类型的文件以及比对文本文件内容。本文将详细分析一个基于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文件管理的资料请关注代码网其它相关文章!
发表评论