基于Python?wxPython開發(fā)文件管理工具
前言
比如瀏覽文件夾、導(dǎo)出文件列表、整理特定類型的文件以及比對(duì)文本文件內(nèi)容。本文將詳細(xì)分析一個(gè)基于wxPython開發(fā)的文件管理工具,該工具提供了多種實(shí)用功能,代碼結(jié)構(gòu)清晰,易于理解和擴(kuò)展。通過學(xué)習(xí)這個(gè)示例,你將掌握如何使用wxPython構(gòu)建圖形界面應(yīng)用程序和實(shí)現(xiàn)常見的文件操作。
全部代碼
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)) # 創(chuàng)建面板和工具欄 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, "導(dǎo)出", wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE), "導(dǎo)出結(jié)果") organize_tool = self.toolbar.AddTool(wx.ID_ANY, "整理", wx.ArtProvider.GetBitmap(wx.ART_REDO), "整理快捷方式") compare_tool = self.toolbar.AddTool(wx.ID_ANY, "比對(duì)", wx.ArtProvider.GetBitmap(wx.ART_LIST_VIEW), "比對(duì)TXT文件") # 實(shí)現(xiàn)工具欄 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) # 創(chuàng)建狀態(tài)欄 self.statusbar = self.CreateStatusBar() self.statusbar.SetStatusText("準(zhǔn)備就緒") # 創(chuàng)建主布局 main_sizer = wx.BoxSizer(wx.VERTICAL) # 顯示當(dāng)前路徑的文本框 self.path_text = wx.TextCtrl(self.panel, style=wx.TE_READONLY) main_sizer.Add(self.path_text, 0, wx.EXPAND | wx.ALL, 5) # 創(chuàng)建列表框用于顯示文件 self.listbox = wx.ListBox(self.panel, style=wx.LB_SINGLE) main_sizer.Add(self.listbox, 1, wx.EXPAND | wx.ALL, 5) # 設(shè)置布局 self.panel.SetSizerAndFit(main_sizer) # 當(dāng)前選擇的目錄 self.current_directory = "" # 文件列表 self.file_list = [] # 居中顯示窗口 self.Center() self.Show() def OnBrowse(self, event): """瀏覽按鈕處理函數(shù)""" # 打開目錄選擇對(duì)話框 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)} 個(gè)文件") 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"遍歷目錄時(shí)發(fā)生錯(cuò)誤: {str(e)}", "錯(cuò)誤", wx.OK | wx.ICON_ERROR) def OnExport(self, event): """導(dǎo)出按鈕處理函數(shù)""" if not self.file_list: wx.MessageBox("沒有可導(dǎo)出的內(nèi)容,請(qǐng)先瀏覽文件夾", "提示", wx.OK | wx.ICON_INFORMATION) return # 打開保存文件對(duì)話框 current_time = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") default_filename = f"文件列表_{current_time}.txt" dlg = wx.FileDialog( self, "導(dǎo)出文件列表", 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"導(dǎo)出時(shí)間: {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"成功導(dǎo)出到 {save_path}") wx.MessageBox(f"已成功導(dǎo)出文件列表到:\n{save_path}", "導(dǎo)出成功", wx.OK | wx.ICON_INFORMATION) except Exception as e: wx.MessageBox(f"導(dǎo)出文件時(shí)發(fā)生錯(cuò)誤: {str(e)}", "錯(cuò)誤", wx.OK | wx.ICON_ERROR) dlg.Destroy() def OnOrganize(self, event): """整理按鈕處理函數(shù)""" if not self.file_list: wx.MessageBox("沒有可整理的內(nèi)容,請(qǐng)先瀏覽文件夾", "提示", wx.OK | wx.ICON_INFORMATION) return # 創(chuàng)建快捷方式目錄 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"創(chuàng)建快捷方式目錄失敗: {str(e)}", "錯(cuò)誤", wx.OK | wx.ICON_ERROR) return # 計(jì)數(shù)器 moved_count = 0 error_count = 0 # 尋找并移動(dòng)快捷方式文件 shortcut_extensions = ['.lnk', '.url'] # Windows快捷方式擴(kuò)展名 for file_path in self.file_list[:]: # 使用副本進(jìn)行遍歷 _, ext = os.path.splitext(file_path) if ext.lower() in shortcut_extensions: try: # 獲取文件名 file_name = os.path.basename(file_path) # 目標(biāo)路徑 dest_path = os.path.join(shortcuts_dir, file_name) # 如果存在同名文件,添加數(shù)字后綴 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 # 移動(dòng)文件 shutil.move(file_path, dest_path) # 從列表中移除 self.file_list.remove(file_path) moved_count += 1 except Exception as e: error_count += 1 print(f"移動(dòng)文件時(shí)出錯(cuò): {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) # 顯示結(jié)果 if moved_count > 0: self.statusbar.SetStatusText(f"已成功移動(dòng) {moved_count} 個(gè)快捷方式文件") wx.MessageBox( f"整理完成\n成功移動(dòng): {moved_count} 個(gè)快捷方式文件\n失敗: {error_count} 個(gè)\n\n快捷方式已移動(dòng)到:\n{shortcuts_dir}", "整理完成", wx.OK | wx.ICON_INFORMATION ) else: self.statusbar.SetStatusText("未找到快捷方式文件") wx.MessageBox("未找到快捷方式文件", "提示", wx.OK | wx.ICON_INFORMATION) def OnCompare(self, event): """比對(duì)文件按鈕處理函數(shù)""" # 創(chuàng)建文件選擇對(duì)話框 dlg = wx.FileDialog( self, "選擇第一個(gè)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() # 選擇第二個(gè)文件 dlg = wx.FileDialog( self, "選擇第二個(gè)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() # 讀取文件內(nèi)容 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比對(duì)文件 diff = list(difflib.unified_diff( content1, content2, fromfile=file1_name, tofile=file2_name, n=3 # 上下文行數(shù) )) # 如果沒有差異 if not diff: wx.MessageBox(f"文件內(nèi)容完全相同:\n{file1_name}\n{file2_name}", "比對(duì)結(jié)果", wx.OK | wx.ICON_INFORMATION) return # 創(chuàng)建比對(duì)結(jié)果窗口 self.ShowCompareResults(file1_name, file2_name, diff) except Exception as e: wx.MessageBox(f"比對(duì)文件時(shí)發(fā)生錯(cuò)誤: {str(e)}", "錯(cuò)誤", wx.OK | wx.ICON_ERROR) def ShowCompareResults(self, file1_name, file2_name, diff_results): """顯示比對(duì)結(jié)果的對(duì)話框""" # 創(chuàng)建對(duì)話框 dlg = wx.Dialog(self, title=f"文件比對(duì)結(jié)果: {file1_name} vs {file2_name}", size=(800, 600)) # 創(chuàng)建布局 sizer = wx.BoxSizer(wx.VERTICAL) # 標(biāo)題標(biāo)簽 title_text = wx.StaticText(dlg, label=f"文件比對(duì)結(jié)果") 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"比對(duì)文件:\n{file1_name}\n{file2_name}") sizer.Add(info_text, 0, wx.ALL | wx.EXPAND, 10) # 創(chuàng)建文本控件顯示比對(duì)結(jié)果 diff_text = wx.TextCtrl(dlg, style=wx.TE_MULTILINE | wx.TE_READONLY | wx.HSCROLL) # 設(shè)置等寬字體便于閱讀差異 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) # 添加導(dǎo)出按鈕 export_btn = wx.Button(dlg, label="導(dǎo)出比對(duì)結(jié)果") sizer.Add(export_btn, 0, wx.ALL | wx.CENTER, 10) # 關(guān)閉按鈕 close_btn = wx.Button(dlg, wx.ID_CLOSE, "關(guān)閉") sizer.Add(close_btn, 0, wx.ALL | wx.CENTER, 10) # 綁定導(dǎo)出按鈕事件 export_btn.Bind(wx.EVT_BUTTON, lambda evt, d=diff_results, f1=file1_name, f2=file2_name: self.ExportCompareResults(d, f1, f2)) # 綁定關(guān)閉按鈕事件 close_btn.Bind(wx.EVT_BUTTON, lambda evt: dlg.EndModal(wx.ID_CLOSE)) # 設(shè)置布局 dlg.SetSizer(sizer) # 顯示對(duì)話框 dlg.ShowModal() dlg.Destroy() def ExportCompareResults(self, diff_results, file1_name, file2_name): """導(dǎo)出比對(duì)結(jié)果""" # 創(chuàng)建保存文件對(duì)話框 current_time = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") default_filename = f"比對(duì)結(jié)果_{current_time}.txt" dlg = wx.FileDialog( self, "保存比對(duì)結(jié)果", 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"文件比對(duì)結(jié)果\n") f.write(f"比對(duì)時(shí)間: {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"比對(duì)結(jié)果已成功導(dǎo)出到:\n{save_path}", "導(dǎo)出成功", wx.OK | wx.ICON_INFORMATION) except Exception as e: wx.MessageBox(f"導(dǎo)出比對(duì)結(jié)果時(shí)發(fā)生錯(cuò)誤: {str(e)}", "錯(cuò)誤", wx.OK | wx.ICON_ERROR) dlg.Destroy() def main(): app = wx.App() frame = FileManagerFrame(None, "文件管理工具") app.MainLoop() if __name__ == "__main__": main()
一、項(xiàng)目概述
這個(gè)文件管理工具具有以下核心功能:
- 瀏覽文件夾:遞歸遍歷指定文件夾中的所有文件
- 顯示文件列表:在列表框中展示文件路徑
- 導(dǎo)出文件列表:將文件列表導(dǎo)出為TXT文檔
- 整理快捷方式:將快捷鏈接文件(.lnk, .url)移動(dòng)到指定文件夾
- 比對(duì)文本文檔:對(duì)比兩個(gè)TXT文件的內(nèi)容差異并顯示結(jié)果
接下來,我們將從界面設(shè)計(jì)、功能實(shí)現(xiàn)到代碼結(jié)構(gòu)等方面進(jìn)行詳細(xì)分析。
二、環(huán)境準(zhǔn)備
在開始之前,確保已安裝wxPython庫:
pip install wxpython
wxPython是Python語言的一套優(yōu)秀的GUI圖形庫,它是Python語言對(duì)wxWidgets C++跨平臺(tái)GUI庫的封裝,提供了豐富的GUI控件和功能。
三、界面設(shè)計(jì)分析
該應(yīng)用程序采用了簡潔而功能齊全的界面設(shè)計(jì),主要包括以下元素:
1. 主窗口框架
應(yīng)用程序使用wx.Frame作為主窗口容器,設(shè)置了標(biāo)題和初始大?。?/p>
class FileManagerFrame(wx.Frame): def __init__(self, parent, title): super(FileManagerFrame, self).__init__(parent, title=title, size=(800, 600))
2. 工具欄設(shè)計(jì)
工具欄是應(yīng)用程序的核心導(dǎo)航元素,包含四個(gè)功能按鈕,每個(gè)按鈕都使用了直觀的圖標(biāo):
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, "導(dǎo)出", wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE), "導(dǎo)出結(jié)果") organize_tool = self.toolbar.AddTool(wx.ID_ANY, "整理", wx.ArtProvider.GetBitmap(wx.ART_REDO), "整理快捷方式") compare_tool = self.toolbar.AddTool(wx.ID_ANY, "比對(duì)", wx.ArtProvider.GetBitmap(wx.ART_LIST_VIEW), "比對(duì)TXT文件") self.toolbar.Realize()
這里使用了wx.ArtProvider提供的標(biāo)準(zhǔn)圖標(biāo),這是一個(gè)很好的實(shí)踐,因?yàn)樗鼈冊(cè)诓煌脚_(tái)上都能保持一致的外觀。
3. 狀態(tài)欄
狀態(tài)欄用于顯示當(dāng)前操作的狀態(tài)信息,提供了良好的用戶反饋:
self.statusbar = self.CreateStatusBar() self.statusbar.SetStatusText("準(zhǔn)備就緒")
4. 主布局設(shè)計(jì)
主界面采用垂直的盒子布局(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)
這里的布局使用了比例設(shè)置,文件列表框設(shè)置為1,可以隨窗口調(diào)整大小而自動(dòng)擴(kuò)展。
四、核心功能實(shí)現(xiàn)分析
1. 文件夾瀏覽功能
瀏覽功能通過OnBrowse方法實(shí)現(xiàn),使用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)} 個(gè)文件") dlg.Destroy()
文件遍歷通過os.walk實(shí)現(xiàn)遞歸遍歷,這是Python處理文件系統(tǒng)的標(biāo)準(zhǔn)方法:
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"遍歷目錄時(shí)發(fā)生錯(cuò)誤: {str(e)}", "錯(cuò)誤", wx.OK | wx.ICON_ERROR)
這里值得注意的是:
- 使用os.path.relpath計(jì)算相對(duì)路徑,使顯示更簡潔
- 添加了異常處理,增強(qiáng)程序的健壯性
2. 導(dǎo)出文件列表功能
導(dǎo)出功能通過OnExport方法實(shí)現(xiàn),使用wx.FileDialog讓用戶選擇保存位置:
def OnExport(self, event): if not self.file_list: wx.MessageBox("沒有可導(dǎo)出的內(nèi)容,請(qǐng)先瀏覽文件夾", "提示", wx.OK | wx.ICON_INFORMATION) return # 生成默認(rèn)文件名(包含時(shí)間戳) current_time = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") default_filename = f"文件列表_{current_time}.txt" dlg = wx.FileDialog( self, "導(dǎo)出文件列表", 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"導(dǎo)出時(shí)間: {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"成功導(dǎo)出到 {save_path}") wx.MessageBox(f"已成功導(dǎo)出文件列表到:\n{save_path}", "導(dǎo)出成功", wx.OK | wx.ICON_INFORMATION) except Exception as e: wx.MessageBox(f"導(dǎo)出文件時(shí)發(fā)生錯(cuò)誤: {str(e)}", "錯(cuò)誤", wx.OK | wx.ICON_ERROR) dlg.Destroy()
這個(gè)功能的亮點(diǎn):
- 使用時(shí)間戳生成默認(rèn)文件名,避免覆蓋
- 添加了文件頭信息,包括路徑和時(shí)間
- 使用wx.FD_OVERWRITE_PROMPT標(biāo)志提示用戶文件已存在
3. 整理快捷方式功能
整理功能通過OnOrganize方法實(shí)現(xiàn),將快捷方式文件移動(dòng)到指定文件夾:
def OnOrganize(self, event): if not self.file_list: wx.MessageBox("沒有可整理的內(nèi)容,請(qǐng)先瀏覽文件夾", "提示", wx.OK | wx.ICON_INFORMATION) return # 創(chuàng)建快捷方式目錄 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"創(chuàng)建快捷方式目錄失敗: {str(e)}", "錯(cuò)誤", wx.OK | wx.ICON_ERROR) return # 計(jì)數(shù)器和文件移動(dòng)邏輯 moved_count = 0 error_count = 0 shortcut_extensions = ['.lnk', '.url'] for file_path in self.file_list[:]: # 使用副本進(jìn)行遍歷 _, ext = os.path.splitext(file_path) if ext.lower() in shortcut_extensions: try: # 文件移動(dòng)邏輯 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"移動(dòng)文件時(shí)出錯(cuò): {str(e)}") # 刷新列表和顯示結(jié)果 # ...
這個(gè)功能的技術(shù)要點(diǎn):
- 使用列表的副本進(jìn)行遍歷,同時(shí)修改原列表
- 處理文件重名情況,通過添加數(shù)字后綴解決
- 使用shutil.move進(jìn)行文件移動(dòng)操作
4. 文件比對(duì)功能
文件比對(duì)是本應(yīng)用的一個(gè)亮點(diǎn)功能,通過OnCompare方法實(shí)現(xiàn):
def OnCompare(self, event): # 選擇第一個(gè)文件 dlg = wx.FileDialog( self, "選擇第一個(gè)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() # 選擇第二個(gè)文件 # ... # 讀取文件內(nèi)容 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比對(duì)文件 diff = list(difflib.unified_diff( content1, content2, fromfile=file1_name, tofile=file2_name, n=3 # 上下文行數(shù) )) # 比對(duì)結(jié)果處理 # ...
比對(duì)結(jié)果顯示通過ShowCompareResults方法實(shí)現(xiàn),創(chuàng)建一個(gè)新對(duì)話框:
def ShowCompareResults(self, file1_name, file2_name, diff_results): # 創(chuàng)建對(duì)話框 dlg = wx.Dialog(self, title=f"文件比對(duì)結(jié)果: {file1_name} vs {file2_name}", size=(800, 600)) # 創(chuàng)建布局和控件 # ... # 使用不同顏色顯示差異 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) # 顯示對(duì)話框 # ...
文件比對(duì)功能的技術(shù)亮點(diǎn):
- 使用Python標(biāo)準(zhǔn)庫difflib進(jìn)行文本比對(duì)
- 采用統(tǒng)一差異格式(unified diff)顯示結(jié)果
- 使用顏色區(qū)分添加、刪除和上下文行,提高可讀性
- 提供導(dǎo)出比對(duì)結(jié)果功能
五、代碼架構(gòu)與設(shè)計(jì)模式分析
1. 類結(jié)構(gòu)設(shè)計(jì)
整個(gè)應(yīng)用程序采用了面向?qū)ο蟮脑O(shè)計(jì),主要由FileManagerFrame類構(gòu)成。這個(gè)類繼承自wx.Frame,負(fù)責(zé)創(chuàng)建主窗口和處理所有事件。這種設(shè)計(jì)的優(yōu)點(diǎn)是將界面和功能封裝在一起,代碼組織清晰。
2. 事件處理機(jī)制
該應(yīng)用采用wxPython的事件驅(qū)動(dòng)模型,通過Bind方法將事件與處理函數(shù)綁定:
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)
事件處理函數(shù)命名采用了On+事件的規(guī)范,使代碼更易讀和維護(hù)。
3. 錯(cuò)誤處理機(jī)制
代碼中廣泛使用了異常處理機(jī)制,提高了程序的健壯性:
try: # 可能出錯(cuò)的代碼 except Exception as e: wx.MessageBox(f"出錯(cuò)信息: {str(e)}", "錯(cuò)誤", wx.OK | wx.ICON_ERROR)
通過友好的錯(cuò)誤提示,提升了用戶體驗(yàn)。
4. 狀態(tài)管理
應(yīng)用程序維護(hù)了當(dāng)前目錄和文件列表兩個(gè)核心狀態(tài)變量:
# 當(dāng)前選擇的目錄 self.current_directory = "" # 文件列表 self.file_list = []
各個(gè)功能模塊都基于這些狀態(tài)變量工作,體現(xiàn)了良好的狀態(tài)管理設(shè)計(jì)。
六、代碼優(yōu)化與擴(kuò)展建議
1. 代碼優(yōu)化點(diǎn)
線程處理:對(duì)于大文件夾的遍歷,可以考慮使用線程處理,避免界面凍結(jié):
import threading def OnBrowse(self, event): # ... # 使用線程處理耗時(shí)操作 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
文件過濾功能:添加文件過濾選項(xiàng),只顯示特定類型的文件:
def TraverseDirectory(self, directory, file_filter="*.*"): # 根據(jù)filter過濾文件 import fnmatch # ... if fnmatch.fnmatch(file, file_filter): # 添加到列表
2. 可擴(kuò)展功能
文件預(yù)覽:添加文本文件內(nèi)容預(yù)覽功能
文件搜索:添加按文件名搜索功能
文件操作:增加復(fù)制、刪除、重命名等基本文件操作
多標(biāo)簽支持:支持同時(shí)瀏覽多個(gè)文件夾
拖放支持:支持文件拖放功能
3.運(yùn)行結(jié)果
以上就是基于Python wxPython開發(fā)文件管理工具的詳細(xì)內(nèi)容,更多關(guān)于Python文件管理的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python??序列化反序列化和異常處理的問題小結(jié)
這篇文章主要介紹了Python?序列化反序列化和異常處理,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-12-12Django搭建MySQL主從實(shí)現(xiàn)讀寫分離
本文主要介紹了Django搭建MySQL主從實(shí)現(xiàn)讀寫分離,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08python光學(xué)仿真通過菲涅耳公式實(shí)現(xiàn)波動(dòng)模型
這篇文章主要介紹了python光學(xué)仿真通過菲涅耳公式實(shí)現(xiàn)波動(dòng)模型的示例解析原理,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2021-10-10python數(shù)字轉(zhuǎn)對(duì)應(yīng)中文的方法總結(jié)
在本篇文章里小編給大家分享的是一篇關(guān)于python數(shù)字轉(zhuǎn)對(duì)應(yīng)中文的方法總結(jié)內(nèi)容,有興趣的朋友們可以跟著猜嘗試測試下。2021-08-08pip matplotlib報(bào)錯(cuò)equired packages can not be built解決
這篇文章主要介紹了pip matplotlib報(bào)錯(cuò)equired packages can not be built解決,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-01-01Python numpy 提取矩陣的某一行或某一列的實(shí)例
下面小編就為大家分享一篇Python numpy 提取矩陣的某一行或某一列的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-04-04