作者:donoot | 版本:v0.11
项目概述
SysDriMan 是一款基于 Python 和 PyQt5 开发的 Windows 磁盘分析与清理工具,旨在帮助用户快速了解磁盘空间使用情况,管理大文件和已安装软件,清理系统垃圾文件。
项目地址:https://github.com/donoot/SysDriMan
功能特性
1. 磁盘空间分析
饼图可视化:直观展示磁盘空间分布情况
递归浏览:双击饼图扇区可进入子目录查看详细分布
空间信息显示:实时显示总空间、已用空间、剩余空间
2. 大文件管理
自动扫描:扫描并列出大于指定阈值的大文件
文件详情:显示文件路径、大小、修改时间、创建时间
列宽可调:表格列宽支持鼠标拖动调节
3. 已安装软件管理
注册表读取:从 Windows 注册表读取所有已安装软件
快速操作:右键菜单支持卸载和修改软件
4. 垃圾文件清理
自动扫描:扫描系统临时目录、回收站等常见垃圾位置
一键清理:支持批量清理选中的垃圾文件(移至回收站)
5. 流光进度条
滚动渐变:参考经典工具"溯雪"的流光效果
实时百分比:中间显示扫描进度百分比
技术架构设计
整体架构
![]()
编辑
模块划分
| 模块 | 职责 | 文件 |
|---|---|---|
| 主窗口 | UI 界面构建和功能集成 | main.py |
| 工具函数 | 管理员权限检查、文件大小格式化 | utils.py |
| 扫描线程 | 后台磁盘扫描、多线程并行处理 | scan_thread.py |
| 软件管理 | 注册表读取、软件卸载 | software_manager.py |
| 垃圾清理 | 垃圾文件扫描、清理 | garbage_cleaner.py |
核心技术实现
1. 多线程并行扫描
问题背景:磁盘扫描是一个耗时操作,如果在主线程中执行会导致 UI 卡顿。
解决方案:使用 Pythonthreading模块结合 Qt 的QThread实现多线程并行扫描。
class ScanWorker(threading.Thread): """扫描工作线程类""" def __init__(self, task_queue, result_queue, size_threshold, stop_event): super().__init__() self.task_queue = task_queue self.result_queue = result_queue self.size_threshold = size_threshold self.stop_event = stop_event def run(self): while not self.stop_event.is_set(): try: dirpath, dirnames, filenames = self.task_queue.get(timeout=1) except: break dir_size = 0 big_files = [] for f in filenames: try: fp = os.path.join(dirpath, f) if os.path.isfile(fp): st = os.stat(fp) size = st.st_size dir_size += size if size >= self.size_threshold: big_files.append((fp, size, ...)) except (PermissionError, OSError): continue self.result_queue.put((dirpath, dir_size, big_files)) self.task_queue.task_done()
关键设计:
使用
Queue实现任务分发和结果收集多个
ScanWorker线程并行处理目录扫描通过
stop_event实现优雅停止使用 Qt 信号机制向主线程传递进度
2. 流光进度条实现
问题背景:用户希望进度条具有流动的视觉效果,类似于经典工具"溯雪"中的流光效果。
解决方案:使用 QTimer 定时更新 QProgressBar 的样式表,实现滚动渐变效果。
def setup_flow_progress_style(self): """设置流光进度条样式""" self.flow_gradient_pos = 0 self.flow_timer = QTimer(self) self.flow_timer.timeout.connect(self.update_flow_animation) base_style = """ QProgressBar { border: 1px solid #666666; border-radius: 4px; background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #4a4a4a, stop:0.5 #3d3d3d, stop:1 #333333); text-align: center; color: #00ffff; font-weight: bold; font-size: 12px; } QProgressBar::chunk { border-radius: 3px; margin: 1px; } """ self.progress_bar.setStyleSheet(base_style) def update_flow_animation(self): """更新流光动画""" self.flow_gradient_pos = (self.flow_gradient_pos + 1) % 100 p = self.flow_gradient_pos / 100.0 style = f""" QProgressBar::chunk {{ background: qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:{(p - 0.3) % 1} transparent, stop:{(p - 0.2) % 1} rgba(0, 200, 255, 0.3), stop:{(p - 0.1) % 1} rgba(0, 220, 255, 0.6), stop:{p % 1} rgba(0, 255, 255, 1), stop:{(p + 0.1) % 1} rgba(0, 220, 255, 0.6), stop:{(p + 0.2) % 1} rgba(0, 200, 255, 0.3), stop:{(p + 0.3) % 1} transparent); }} """ self.progress_bar.setStyleSheet(style)关键设计:
使用
rgba颜色值实现透明度渐变通过取模运算实现无缝循环
50ms 定时器间隔保证动画流畅
3. Matplotlib 饼图嵌入 Qt 界面
问题背景:需要在 PyQt5 界面中嵌入交互式饼图,支持双击进入子目录。
解决方案:使用FigureCanvasQTAgg将 Matplotlib 图表嵌入 Qt 界面,并绑定鼠标事件。
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas from matplotlib.figure import Figure class MainWindow(QMainWindow): def __init__(self): ... self.fig = Figure(figsize=(5, 5)) self.canvas = FigureCanvas(self.fig) self.left_layout.addWidget(self.canvas) self.canvas.mpl_connect('button_press_event', self.on_pie_click) def on_pie_click(self, event): """处理饼图双击事件""" if event.dblclick and hasattr(self, 'wedges'): for i, wedge in enumerate(self.wedges): if wedge.contains(event)[0]: label = self.pie_labels[i] if label == '其他目录': return new_path = os.path.join(self.current_path, label) if os.path.isdir(new_path): self.path_history.append(self.current_path) self.current_path = new_path self.update_pie_chart() break关键设计:
使用
FigureCanvasQTAgg作为 Qt 控件通过
mpl_connect绑定鼠标事件使用
wedge.contains(event)判断点击位置维护路径历史支持返回上层
4. 管理员权限自动提升
问题背景:访问系统目录和注册表需要管理员权限,普通用户运行会遇到权限不足问题。
解决方案:在程序启动时检查权限,若无管理员权限则自动提升。
import ctypes import sys def is_admin(): """检查当前进程是否以管理员身份运行""" try: return ctypes.windll.shell32.IsUserAnAdmin() except: return False def run_as_admin(): """以管理员身份重新启动程序""" if sys.platform == 'win32': script = os.path.abspath(sys.argv[0]) params = ' '.join(['"' + arg + '"' for arg in sys.argv[1:]]) ctypes.windll.shell32.ShellExecuteW( None, "runas", sys.executable, f'"{script}" {params}', None, 1 ) if __name__ == "__main__": if not is_admin(): run_as_admin() sys.exit(0) app = QApplication(sys.argv) window = MainWindow() window.show() sys.exit(app.exec_())关键设计:
使用
IsUserAnAdmin()检查权限使用
ShellExecuteW以runas方式启动保留命令行参数传递
5. 中文字体配置
问题背景:Matplotlib 默认不支持中文,中文标签会显示为方块或乱码。
解决方案:检测系统可用字体并配置 Matplotlib 使用中文字体。
import matplotlib.font_manager as fm def setup_matplotlib_font(): """设置matplotlib中文字体""" available_fonts = [f.name for f in fm.fontManager.ttflist] preferred_fonts = [ 'SimHei', 'Microsoft YaHei', 'SimSun', 'KaiTi', 'Heiti SC', 'STHeiti' ] selected_font = None for font in preferred_fonts: if font in available_fonts: selected_font = font break if selected_font: matplotlib.rcParams['font.sans-serif'] = [selected_font] matplotlib.rcParams['font.family'] = 'sans-serif' matplotlib.rcParams['axes.unicode_minus'] = False setup_matplotlib_font()
关键设计:
枚举系统可用字体列表
按优先级选择最合适的中文字体
关闭 Unicode 负号替换
遇到的问题与解决方案
问题 1:QProgressBar 样式频繁更新导致闪烁
现象:每次更新进度条样式表时,界面会出现短暂闪烁。
原因:频繁调用setStyleSheet会触发控件重绘。
解决方案:
初始化时设置基础样式,动画更新时只修改
::chunk部分使用
QTimer控制更新频率(50ms)
问题 2:多线程资源竞争
现象:多个线程同时写入结果字典时可能出现数据不一致。
原因:Python 的字典不是线程安全的。
解决方案:
使用
Queue收集结果,在主线程中汇总避免多个线程直接修改共享数据结构
问题 3:Windows 控制台中文乱码
现象:程序输出的中文路径在控制台显示为乱码。
原因:Windows 控制台默认使用 GBK 编码,而 Python 使用 UTF-8。
解决方案:
if sys.platform == 'win32': ctypes.windll.kernel32.SetConsoleCP(65001) ctypes.windll.kernel32.SetConsoleOutputCP(65001) os.environ['PYTHONUTF8'] = '1'
问题 4:Matplotlib 饼图标签重叠
现象:当目录名称较长时,饼图标签会重叠。
解决方案:
设置
labeldistance=1.15增加标签距离使用较小的字体大小(8-10pt)
限制显示的目录数量(前 10 个 + 其他)
项目运行
环境要求
| 依赖 | 安装命令 |
|---|---|
| PyQt5 | pip install PyQt5 |
| Matplotlib | pip install matplotlib |
| psutil | pip install psutil |
| send2trash | pip install send2trash |
启动方式
cd src python main.py
注意:程序会自动检查管理员权限,若无权限会弹出 UAC 提示。
总结与展望
已实现功能
✅ 磁盘空间分析与可视化
✅ 多线程并行扫描
✅ 流光进度条动画
✅ 大文件管理
✅ 软件管理(注册表读取、卸载)
✅ 垃圾文件清理
✅ 管理员权限自动提升
✅ 中文路径支持
未来计划
🔲 添加磁盘健康检测功能
🔲 支持导出分析报告(PDF/Excel)
🔲 添加文件类型统计
🔲 优化扫描算法,支持增量扫描
🔲 添加快捷键支持
🔲 支持深色/浅色主题切换
结语
SysDriMan 项目展示了如何使用 PyQt5 构建功能完善的桌面应用,涵盖了多线程编程、数据可视化、系统权限管理等多个技术要点。希望本文能对正在学习 PyQt5 开发的小伙伴有所帮助!
如果您对项目有任何建议或问题,欢迎在 GitHub 仓库中提交 Issue 或 Pull Request。
项目地址:https://github.com/donoot/SysDriMan
原创不易,如果本文对您有帮助,请点赞支持!