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文件名提取的资料请关注脚本之家其它相关文章!
