Python+PyQt5實現(xiàn)文件夾結(jié)構(gòu)映射工具
概述
在日常工作中,我們經(jīng)常需要對文件夾結(jié)構(gòu)進行復(fù)制和備份,比如僅復(fù)制一級目錄,或者完整復(fù)制多級目錄,有時還希望連同文件名及后綴創(chuàng)建空文件。手動操作既費時又容易出錯。為了解決這個問題,本文將帶來一款基于PyQt5開發(fā)的「文件夾結(jié)構(gòu)映射工具」,支持拖拽選取路徑,三種復(fù)制模式,操作簡單直觀,極大提升工作效率。
本工具代碼精煉,功能實用,界面美觀,適合文件管理、項目結(jié)構(gòu)遷移、代碼備份等多種場景使用。文章將深入解析程序設(shè)計思路、界面布局、功能實現(xiàn),并附上完整源碼下載,方便讀者學(xué)習(xí)和二次開發(fā)。
功能亮點
路徑拖拽與瀏覽雙重選擇:支持從資源管理器拖拽文件夾路徑到輸入框,也可以點擊“瀏覽”按鈕選擇目錄,操作靈活便捷。
多復(fù)制模式支持:
- 僅復(fù)制一級目錄結(jié)構(gòu)(不進入子文件夾)
- 復(fù)制多級目錄結(jié)構(gòu)(僅文件夾,無文件)
- 復(fù)制多級目錄結(jié)構(gòu)并創(chuàng)建空文件(文件名與后綴保持一致)
路徑有效性校驗:自動檢測源路徑和目標路徑是否合理,防止錯誤操作。
界面簡潔美觀:采用淡雅配色和流暢交互,按鈕及控件布局合理,使用體驗良好。
詳細提示反饋:復(fù)制完成后彈窗顯示創(chuàng)建文件夾數(shù),異常情況及時警告。
展示效果
- 左側(cè)文本框支持拖拽粘貼目錄路徑
- 右側(cè)按鈕可彈出系統(tǒng)文件夾選擇窗口
- 中間清晰顯示復(fù)制模式單選選項
- 右下角“開始映射結(jié)構(gòu)”按鈕啟動復(fù)制
- 復(fù)制完成彈窗告知成功與否
軟件使用步驟
1.選擇源路徑
可直接拖拽文件夾至左側(cè)輸入框,或點擊“瀏覽”按鈕彈出選擇窗口,選擇想復(fù)制的文件夾。
2.選擇目標路徑
同樣支持拖拽或瀏覽選擇,指定復(fù)制結(jié)果保存位置。注意目標路徑不能是源路徑的子目錄。
3.選擇復(fù)制模式
- 僅復(fù)制一級目錄
- 復(fù)制多級目錄結(jié)構(gòu),不含文件
- 復(fù)制多級目錄結(jié)構(gòu)并創(chuàng)建空文件
- 根據(jù)需求選擇。
4.點擊“開始映射結(jié)構(gòu)”
程序?qū)催x定模式復(fù)制目錄結(jié)構(gòu)。完成后彈窗顯示操作結(jié)果。
5.查看目標路徑
目標路徑將生成對應(yīng)的目錄結(jié)構(gòu)(及空文件),驗證復(fù)制是否正確。
代碼解析
1. 主窗口設(shè)計(FolderCopyApp)
繼承自QWidget,設(shè)置窗口標題、尺寸和基礎(chǔ)樣式,調(diào)用init_ui()方法構(gòu)建界面。
self.setWindowTitle("?? 文件夾結(jié)構(gòu)映射工具") self.setGeometry(300, 300, 600, 350) self.setStyleSheet(""" background-color: #f4f6f9; font-family: "Segoe UI"; font-size:14px; """)
2. 拖拽路徑輸入框(DropLineEdit)
繼承自QLineEdit,重寫dragEnterEvent和dropEvent實現(xiàn)路徑拖拽識別,提升用戶體驗。
def dragEnterEvent(self, e): if e.mimeData().hasUrls(): e.accept() else: e.ignore() def dropEvent(self, e): if e.mimeData().hasUrls(): path = e.mimeData().urls()[0].toLocalFile() self.setText(path)
3. 界面布局與控件綁定
使用QVBoxLayout整體垂直布局
每個路徑輸入?yún)^(qū)用QHBoxLayout橫向放置文本框和瀏覽按鈕
復(fù)制模式通過QGroupBox和QRadioButton呈現(xiàn),默認選擇一級目錄復(fù)制
“開始映射結(jié)構(gòu)”按鈕綁定復(fù)制功能
self.copy_btn.clicked.connect(self.copy_structure)
4. 復(fù)制結(jié)構(gòu)核心邏輯
copy_structure函數(shù)根據(jù)模式執(zhí)行不同目錄復(fù)制:
一級目錄復(fù)制
or name in os.listdir(source): full_path = os.path.join(source, name) if os.path.isdir(full_path): os.makedirs(os.path.join(target, name), exist_ok=True)
多級目錄復(fù)制
for root, dirs, files in os.walk(source): rel_path = os.path.relpath(root, source) target_dir = os.path.join(target, rel_path) os.makedirs(target_dir, exist_ok=True)
- **多級目錄復(fù)制 + 空文件**
if mode == "with_files": for file in files: open(os.path.join(target_dir, file), 'w').close()
5. 異常處理和提示
校驗路徑有效性,防止錯誤操作
捕獲異常,彈窗反饋錯誤
復(fù)制完成后提示創(chuàng)建目錄數(shù)量
源碼下載
import sys import os from PyQt5.QtWidgets import ( QApplication, QWidget, QLabel, QLineEdit, QPushButton, QVBoxLayout, QHBoxLayout, QFileDialog, QRadioButton, QGroupBox, QMessageBox ) from PyQt5.QtCore import Qt class DropLineEdit(QLineEdit): def __init__(self, *args): super().__init__(*args) self.setAcceptDrops(True) def dragEnterEvent(self, e): if e.mimeData().hasUrls(): e.accept() else: e.ignore() def dropEvent(self, e): if e.mimeData().hasUrls(): path = e.mimeData().urls()[0].toLocalFile() self.setText(path) class FolderCopyApp(QWidget): def __init__(self): super().__init__() self.setWindowTitle("?? 文件夾結(jié)構(gòu)映射工具") self.setGeometry(300, 300, 600, 350) self.setStyleSheet(""" background-color: #f4f6f9; font-family: "Segoe UI"; font-size:14px; """) self.init_ui() def init_ui(self): layout = QVBoxLayout() # 源路徑 source_layout = QHBoxLayout() self.source_input = DropLineEdit() browse_source = QPushButton("瀏覽") browse_source.setFixedWidth(60) browse_source.setStyleSheet(self.button_style()) browse_source.clicked.connect(self.select_source) self.add_field("源路徑(拖拽或選擇)", self.source_input, browse_source, layout, source_layout) # 目標路徑 target_layout = QHBoxLayout() self.target_input = DropLineEdit() browse_target = QPushButton("瀏覽") browse_target.setFixedWidth(60) browse_target.setStyleSheet(self.button_style()) browse_target.clicked.connect(self.select_target) self.add_field("目標路徑(拖拽或選擇)", self.target_input, browse_target, layout, target_layout) # 模式選擇 self.mode_group = QGroupBox("選擇復(fù)制模式") self.mode_group.setStyleSheet("QGroupBox { font-weight: bold; }") mode_layout = QVBoxLayout() self.level1_radio = QRadioButton("僅復(fù)制一級目錄結(jié)構(gòu)") self.multilevel_radio = QRadioButton("復(fù)制多級目錄結(jié)構(gòu)(不含文件)") self.with_files_radio = QRadioButton("復(fù)制多級結(jié)構(gòu) + 空文件(保留名稱與后綴)") self.level1_radio.setChecked(True) mode_layout.addWidget(self.level1_radio) mode_layout.addWidget(self.multilevel_radio) mode_layout.addWidget(self.with_files_radio) self.mode_group.setLayout(mode_layout) layout.addWidget(self.mode_group) # 操作按鈕 self.copy_btn = QPushButton("?? 開始映射結(jié)構(gòu)") self.copy_btn.setStyleSheet(self.button_style()) self.copy_btn.clicked.connect(self.copy_structure) layout.addWidget(self.copy_btn) self.setLayout(layout) def add_field(self, label_text, line_edit, button, layout, sublayout): label = QLabel(label_text) label.setStyleSheet("color: #333;") layout.addWidget(label) sublayout.addWidget(line_edit) sublayout.addWidget(button) layout.addLayout(sublayout) def button_style(self): return """ QPushButton { background-color: #5c9ded; color: white; border: none; padding: 6px 12px; border-radius: 4px; font-family: "Segoe UI", "Roboto", "Helvetica Neue", Arial, sans-serif; font-weight: bold; } QPushButton:hover { background-color: #468be6; } """ def select_source(self): path = QFileDialog.getExistingDirectory(self, "選擇源目錄") if path: self.source_input.setText(path) def select_target(self): path = QFileDialog.getExistingDirectory(self, "選擇目標目錄") if path: self.target_input.setText(path) def copy_structure(self): source = self.source_input.text().strip() target = self.target_input.text().strip() mode = "level1" if self.level1_radio.isChecked() else \ "multilevel" if self.multilevel_radio.isChecked() else "with_files" if not source or not target: QMessageBox.warning(self, "錯誤", "請設(shè)置源路徑和目標路徑") return if not os.path.exists(source): QMessageBox.warning(self, "錯誤", "源路徑無效") return if os.path.commonpath([source]) == os.path.commonpath([source, target]): QMessageBox.warning(self, "錯誤", "目標路徑不能位于源路徑內(nèi)部") return try: created = 0 if mode == "level1": # 僅復(fù)制一級目錄結(jié)構(gòu)(直接子文件夾) for name in os.listdir(source): full_path = os.path.join(source, name) if os.path.isdir(full_path): os.makedirs(os.path.join(target, name), exist_ok=True) created += 1 else: for root, dirs, files in os.walk(source): rel_path = os.path.relpath(root, source) target_dir = os.path.join(target, rel_path) os.makedirs(target_dir, exist_ok=True) created += 1 if mode == "with_files": for file in files: try: open(os.path.join(target_dir, file), 'w').close() except Exception as fe: print(f"無法創(chuàng)建文件:{file}, 錯誤:{fe}") QMessageBox.information(self, "完成", f"結(jié)構(gòu)復(fù)制完成,創(chuàng)建文件夾數(shù):{created}") except Exception as e: QMessageBox.critical(self, "錯誤", str(e)) if __name__ == "__main__": app = QApplication(sys.argv) window = FolderCopyApp() window.show() sys.exit(app.exec_())
總結(jié)
這款基于PyQt5的「文件夾結(jié)構(gòu)映射工具」功能實用,代碼清晰,界面友好,適合所有需要目錄結(jié)構(gòu)復(fù)制的場景。通過拖拽輸入和多復(fù)制模式滿足不同用戶需求。本文不僅介紹了工具功能,還詳細剖析了關(guān)鍵代碼和實現(xiàn)細節(jié)。希望對您學(xué)習(xí)PyQt5 GUI開發(fā)、文件系統(tǒng)操作提供有價值的參考。
到此這篇關(guān)于Python+PyQt5實現(xiàn)文件夾結(jié)構(gòu)映射工具的文章就介紹到這了,更多相關(guān)Python文件夾結(jié)構(gòu)映射內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python數(shù)據(jù)分析之聚類分析(cluster analysis)
聚類分析本身不是一個特定的算法,而是要解決的一般任務(wù)。它可以通過各種算法來實現(xiàn),這些算法在理解群集的構(gòu)成以及如何有效地找到它們方面存在顯著差異。這篇文章主要介紹了python數(shù)據(jù)分析之聚類分析(cluster analysis),需要的朋友可以參考下2021-11-11Python使用Tkinter實現(xiàn)滾動抽獎器效果
Tkinter 是 Python 的標準 GUI(Graphical User Interface,圖形用戶接口)庫,Python 使用 Tkinter 可以快速地創(chuàng)建 GUI 應(yīng)用程序。這篇文章主要介紹了Python使用Tkinter實現(xiàn)滾動抽獎器,需要的朋友可以參考下2020-01-01Python實現(xiàn)tuple和list的轉(zhuǎn)換方式
在Python中,可以使用內(nèi)置的list()和tuple()函數(shù)將tuple和list相互轉(zhuǎn)換,tuple是不可變的,而list是可變的,轉(zhuǎn)換時要注意性能考慮2024-12-12python自動統(tǒng)計zabbix系統(tǒng)監(jiān)控覆蓋率的示例代碼
這篇文章主要介紹了python自動統(tǒng)計zabbix系統(tǒng)監(jiān)控覆蓋率的示例代碼,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-04-04Python數(shù)據(jù)結(jié)構(gòu)之順序表的實現(xiàn)代碼示例
這篇文章主要介紹了Python數(shù)據(jù)結(jié)構(gòu)之順序表的實現(xiàn)代碼示例,簡單介紹了順序表的相關(guān)內(nèi)容,然后分享了其代碼示例,具有一定參考價值,需要的朋友可以了解下。2017-11-11