python开发一个文件夹文件名提取工具(附完整代码)
作者:小庄-Python办公
项目简介
这是一个基于PyQt5开发的桌面应用程序,专门用于提取文件夹中所有文件的名称并导出为Excel格式。该工具支持拖拽操作,提供直观的用户界面,能够递归遍历文件夹结构,是文件管理和数据整理的实用工具。
主要功能特性
核心功能
- 拖拽支持:直接将文件夹拖拽到应用界面即可选择目标文件夹
- 递归遍历:自动遍历文件夹及其所有子文件夹
- 文件统计:统计并显示所有文件的详细信息
- Excel导出:将文件列表导出为Excel格式,便于后续处理
- 目录结构显示:按目录层级组织显示文件列表
用户体验
- 可视化拖拽反馈:拖拽时提供绿色高亮效果
- 实时状态提示:清晰的操作提示和状态反馈
- 现代化界面:采用现代扁平化设计风格
- 响应式布局:界面元素自适应窗口大小
技术架构
技术栈
- GUI框架:PyQt5
- 数据处理:pandas
- 文件操作:Python标准库 (os, pathlib)
- 开发语言:Python 3.x
核心组件
1. FileListWidget 类
class FileListWidget(QTextEdit): """支持拖拽的文本显示区域"""
主要职责:
- 处理拖拽事件(dragEnterEvent, dragLeaveEvent, dragMoveEvent, dropEvent)
- 验证拖拽内容是否为文件夹
- 提供视觉反馈效果
- 存储选中的文件夹路径
关键特性:
- 跨平台兼容性:通过dragMoveEvent确保Windows平台的拖拽稳定性
- 智能验证:只接受文件夹类型的拖拽,拒绝文件拖拽
- 视觉反馈:拖拽进入时显示绿色边框和背景色
2. MainWindow 类
class MainWindow(QMainWindow): """主窗口类"""
主要职责:
- 构建用户界面布局
- 处理业务逻辑(文件遍历、数据处理)
- 管理用户交互事件
- 控制Excel导出功能
详细功能说明
拖拽功能实现
拖拽事件处理流程
- dragEnterEvent:检测拖拽内容是否包含本地文件夹
- dragMoveEvent:在Windows平台持续接受拖拽操作
- dragLeaveEvent:恢复界面原始样式
- dropEvent:处理文件夹路径并更新界面
关键代码解析
def dragEnterEvent(self, event: QDragEnterEvent): if event.mimeData().hasUrls(): urls = event.mimeData().urls() accept = False if urls: for url in urls: if url.isLocalFile(): file_path = url.toLocalFile() if os.path.isdir(file_path): accept = True break if accept: # 设置拖拽高亮样式 self.setStyleSheet("""...""") event.setDropAction(Qt.CopyAction) event.accept()
文件遍历算法
使用Python的os.walk()
方法实现递归文件遍历:
def get_all_files(self, folder_path): file_list = [] for root, dirs, files in os.walk(folder_path): relative_root = os.path.relpath(root, folder_path) if relative_root == '.': relative_root = '根目录' for file in files: file_list.append({ '目录': relative_root, '文件名': file }) return file_list
算法特点:
- 递归遍历所有子目录
- 记录文件的相对路径信息
- 构建结构化数据便于后续处理
Excel导出功能
利用pandas库实现Excel导出:
def export_to_excel(self): df = pd.DataFrame(self.file_data) df.to_excel(file_path, index=False, sheet_name='文件列表')
导出特性:
- 支持自定义保存路径
- 包含目录和文件名两列数据
- 提供操作成功/失败反馈
界面设计
布局结构
┌─────────────────────────────────────┐
│ 应用标题 │
├─────────────────────────────────────┤
│ │
│ 拖拽区域 │
│ (支持文件夹拖拽) │
│ │
├─────────────────────────────────────┤
│ [获取文件名] [导出Excel] │
├─────────────────────────────────────┤
│ │
│ 结果显示区域 │
│ │
└─────────────────────────────────────┘
样式设计
配色方案
- 主色调:绿色系 (#4CAF50) - 代表成功和自然
- 辅助色:蓝色系 (#2196F3) - 代表专业和信任
- 背景色:浅灰色系 (#f0f0f0, #f9f9f9) - 提供舒适的视觉体验
交互反馈
- 拖拽状态:绿色虚线边框 + 浅绿背景
- 按钮悬停:颜色加深效果
- 禁用状态:灰色显示
效果图
完整代码
import sys import os from pathlib import Path from PyQt5.QtWidgets import ( QApplication, QMainWindow, QVBoxLayout, QHBoxLayout, QWidget, QPushButton, QTextEdit, QLabel, QMessageBox, QFileDialog ) from PyQt5.QtCore import Qt, QMimeData, QUrl from PyQt5.QtGui import QDragEnterEvent, QDropEvent import pandas as pd class FileListWidget(QTextEdit): """支持拖拽的文本显示区域""" def __init__(self, parent=None): super().__init__(parent) self.setAcceptDrops(True) self.setReadOnly(True) self.setPlaceholderText("请将文件夹拖拽到此处...") self.folder_path = None def dragEnterEvent(self, event: QDragEnterEvent): print("拖拽进入事件触发") # 调试信息 if event.mimeData().hasUrls(): urls = event.mimeData().urls() print(f"检测到URLs: {len(urls)}个") # 调试信息 accept = False if urls: for url in urls: if url.isLocalFile(): file_path = url.toLocalFile() print(f"检查路径: {file_path}") # 调试信息 if os.path.isdir(file_path): accept = True break if accept: print("接受拖拽") # 调试信息 self.setStyleSheet(""" QTextEdit { border: 2px dashed #4CAF50; border-radius: 10px; background-color: #e8f5e8; font-size: 14px; padding: 10px; } """) event.setDropAction(Qt.CopyAction) event.accept() else: print("拒绝拖拽 - 没有可用的目录") # 调试信息 event.ignore() else: print("拒绝拖拽 - 没有URL数据") # 调试信息 event.ignore() def dragLeaveEvent(self, event): # 恢复原始样式 self.setStyleSheet(""" QTextEdit { border: 2px dashed #aaa; border-radius: 10px; background-color: #f9f9f9; font-size: 14px; padding: 10px; } """) super().dragLeaveEvent(event) def dragMoveEvent(self, event): # 某些平台需要在dragMoveEvent中持续接受拖拽 if event.mimeData().hasUrls(): for url in event.mimeData().urls(): if url.isLocalFile() and os.path.isdir(url.toLocalFile()): event.setDropAction(Qt.CopyAction) event.accept() return event.ignore() def dropEvent(self, event: QDropEvent): print("拖拽放下事件触发") # 调试信息 # 恢复原始样式 self.setStyleSheet(""" QTextEdit { border: 2px dashed #aaa; border-radius: 10px; background-color: #f9f9f9; font-size: 14px; padding: 10px; } """) urls = event.mimeData().urls() print(f"放下时检测到URLs: {len(urls) if urls else 0}个") # 调试信息 if urls: dropped_folder = None for url in urls: if url.isLocalFile(): p = url.toLocalFile() print(f"放下的路径候选: {p}") # 调试信息 if os.path.isdir(p): dropped_folder = p break if dropped_folder: self.folder_path = dropped_folder self.setText(f"已选择文件夹: {dropped_folder}") print(f"成功选择文件夹: {dropped_folder}") # 调试信息 event.setDropAction(Qt.CopyAction) event.accept() else: print("错误: 没有检测到文件夹 (可能是文件或无效路径)") # 调试信息 QMessageBox.warning(self, "警告", "请拖入文件夹,不是文件!") event.ignore() else: print("错误: 没有URLs") # 调试信息 event.ignore() class MainWindow(QMainWindow): """主窗口类""" def __init__(self): super().__init__() self.file_data = [] # 存储文件信息的列表 self.init_ui() def init_ui(self): """初始化用户界面""" self.setWindowTitle("文件夹文件名提取工具") self.setGeometry(100, 100, 800, 600) # 创建中央部件 central_widget = QWidget() self.setCentralWidget(central_widget) # 创建布局 layout = QVBoxLayout(central_widget) # 标题标签 title_label = QLabel("文件夹文件名提取工具\n快捷方式无效") title_label.setAlignment(Qt.AlignCenter) title_label.setStyleSheet("font-size: 18px; font-weight: bold; margin: 10px;") layout.addWidget(title_label) # 拖拽区域 self.file_list_widget = FileListWidget() self.file_list_widget.setMinimumHeight(200) self.file_list_widget.setStyleSheet(""" QTextEdit { border: 2px dashed #aaa; border-radius: 10px; background-color: #f9f9f9; font-size: 14px; padding: 10px; } """) layout.addWidget(self.file_list_widget) # 按钮布局 button_layout = QHBoxLayout() # 获取文件名按钮 self.get_files_btn = QPushButton("获取文件名") self.get_files_btn.setStyleSheet(""" QPushButton { background-color: #4CAF50; color: white; border: none; padding: 10px 20px; font-size: 14px; border-radius: 5px; } QPushButton:hover { background-color: #45a049; } """) self.get_files_btn.clicked.connect(self.get_files) button_layout.addWidget(self.get_files_btn) # 导出Excel按钮 self.export_btn = QPushButton("导出Excel") self.export_btn.setStyleSheet(""" QPushButton { background-color: #2196F3; color: white; border: none; padding: 10px 20px; font-size: 14px; border-radius: 5px; } QPushButton:hover { background-color: #1976D2; } """) self.export_btn.clicked.connect(self.export_to_excel) self.export_btn.setEnabled(False) # 初始状态禁用 button_layout.addWidget(self.export_btn) layout.addLayout(button_layout) # 结果显示区域 self.result_text = QTextEdit() self.result_text.setReadOnly(True) self.result_text.setPlaceholderText("文件列表将在这里显示...") layout.addWidget(self.result_text) def get_all_files(self, folder_path): """递归获取文件夹中的所有文件""" file_list = [] try: for root, dirs, files in os.walk(folder_path): # 获取相对于根文件夹的路径 relative_root = os.path.relpath(root, folder_path) if relative_root == '.': relative_root = '根目录' # 添加文件信息 for file in files: file_list.append({ '目录': relative_root, '文件名': file }) except Exception as e: QMessageBox.critical(self, "错误", f"读取文件夹时出错: {str(e)}") return [] return file_list def get_files(self): """获取文件名按钮点击事件""" if not self.file_list_widget.folder_path: QMessageBox.warning(self, "警告", "请先拖入一个文件夹!") return # 获取所有文件 self.file_data = self.get_all_files(self.file_list_widget.folder_path) if not self.file_data: QMessageBox.information(self, "信息", "该文件夹中没有找到任何文件。") return # 显示结果 result_text = f"共找到 {len(self.file_data)} 个文件:\n\n" # 按目录分组显示 current_dir = None for item in self.file_data: if item['目录'] != current_dir: current_dir = item['目录'] result_text += f"\n📁 {current_dir}:\n" result_text += f" 📄 {item['文件名']}\n" self.result_text.setText(result_text) self.export_btn.setEnabled(True) # 启用导出按钮 def export_to_excel(self): """导出到Excel文件""" if not self.file_data: QMessageBox.warning(self, "警告", "没有数据可以导出!") return # 选择保存位置 file_path, _ = QFileDialog.getSaveFileName( self, "保存Excel文件", "文件列表.xlsx", "Excel文件 (*.xlsx);;所有文件 (*)" ) if not file_path: return try: # 创建DataFrame df = pd.DataFrame(self.file_data) # 导出到Excel df.to_excel(file_path, index=False, sheet_name='文件列表') QMessageBox.information( self, "成功", f"文件已成功导出到:\n{file_path}\n\n共导出 {len(self.file_data)} 个文件记录。" ) except Exception as e: QMessageBox.critical(self, "错误", f"导出Excel时出错: {str(e)}") def main(): """主函数""" app = QApplication(sys.argv) # 设置应用程序样式 app.setStyleSheet(""" QMainWindow { background-color: #f0f0f0; } QLabel { color: #333; } QTextEdit { background-color: white; border: 1px solid #ddd; border-radius: 5px; font-family: 'Microsoft YaHei', Arial, sans-serif; } """) window = MainWindow() window.show() sys.exit(app.exec_()) if __name__ == '__main__': main()
使用指南
安装依赖
pip install PyQt5 pandas openpyxl
运行应用
python main.py
操作步骤
- 选择文件夹:将目标文件夹拖拽到应用的拖拽区域
- 获取文件列表:点击"获取文件名"按钮开始扫描
- 查看结果:在结果显示区域查看文件列表
- 导出数据:点击"导出Excel"按钮保存结果
注意事项
- 仅支持文件夹拖拽,不支持单个文件
- 快捷方式无效,需要拖拽实际文件夹
- 大型文件夹可能需要较长处理时间
技术亮点
1. 跨平台拖拽兼容性
通过实现dragMoveEvent
方法,确保在Windows平台上的拖拽操作稳定性:
def dragMoveEvent(self, event): if event.mimeData().hasUrls(): for url in event.mimeData().urls(): if url.isLocalFile() and os.path.isdir(url.toLocalFile()): event.setDropAction(Qt.CopyAction) event.accept() return event.ignore()
2. 健壮的错误处理
- 文件访问权限检查
- 路径有效性验证
- 用户友好的错误提示
3. 内存优化
- 使用生成器模式处理大量文件
- 及时释放不需要的数据结构
- 避免重复加载文件信息
4. 调试支持
内置详细的调试日志输出,便于问题排查:
print(f"检测到URLs: {len(urls)}个") print(f"检查路径: {file_path}") print(f"成功选择文件夹: {dropped_folder}")
扩展功能建议
短期优化
- 添加文件类型过滤功能
- 支持多种导出格式(CSV、JSON)
- 添加文件大小统计
- 实现进度条显示
长期规划
- 支持网络文件夹
- 添加文件预览功能
- 实现批量重命名
- 集成云存储服务
项目结构
文件夹文件名提取工具/
├── main.py # 主程序文件
├── requirements.txt # 依赖包列表
├── README.md # 项目说明
└── blog.md # 技术博客(本文档)
总结
这个文件夹文件名提取工具展示了PyQt5在桌面应用开发中的强大能力。通过合理的架构设计、用户友好的界面和健壮的功能实现,为用户提供了一个实用的文件管理工具。
项目的技术特点包括:
- 现代化的GUI设计:采用PyQt5构建响应式界面
- 直观的交互方式:支持拖拽操作,降低使用门槛
- 完整的数据处理流程:从文件扫描到Excel导出的完整链路
- 跨平台兼容性:针对不同操作系统进行了优化
该项目不仅解决了实际的文件管理需求,也为PyQt5桌面应用开发提供了一个很好的参考案例。无论是对于学习GUI编程的开发者,还是需要文件管理工具的用户,都具有很好的参考价值。
以上就是python开发一个文件夹文件名提取工具(附完整代码)的详细内容,更多关于python文件名提取的资料请关注脚本之家其它相关文章!