news 2026/7/23 1:37:22

【实战项目】基于 PyQt5 开发 Windows 磁盘分析与清理工具

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【实战项目】基于 PyQt5 开发 Windows 磁盘分析与清理工具

作者: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()检查权限

  • 使用ShellExecuteWrunas方式启动

  • 保留命令行参数传递

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 个 + 其他)


项目运行

环境要求

依赖安装命令
PyQt5pip install PyQt5
Matplotlibpip install matplotlib
psutilpip install psutil
send2trashpip install send2trash

启动方式

cd src python main.py

注意:程序会自动检查管理员权限,若无权限会弹出 UAC 提示。


总结与展望

已实现功能

  1. ✅ 磁盘空间分析与可视化

  2. ✅ 多线程并行扫描

  3. ✅ 流光进度条动画

  4. ✅ 大文件管理

  5. ✅ 软件管理(注册表读取、卸载)

  6. ✅ 垃圾文件清理

  7. ✅ 管理员权限自动提升

  8. ✅ 中文路径支持

未来计划

  1. 🔲 添加磁盘健康检测功能

  2. 🔲 支持导出分析报告(PDF/Excel)

  3. 🔲 添加文件类型统计

  4. 🔲 优化扫描算法,支持增量扫描

  5. 🔲 添加快捷键支持

  6. 🔲 支持深色/浅色主题切换


结语

SysDriMan 项目展示了如何使用 PyQt5 构建功能完善的桌面应用,涵盖了多线程编程、数据可视化、系统权限管理等多个技术要点。希望本文能对正在学习 PyQt5 开发的小伙伴有所帮助!

如果您对项目有任何建议或问题,欢迎在 GitHub 仓库中提交 Issue 或 Pull Request。

项目地址:https://github.com/donoot/SysDriMan


原创不易,如果本文对您有帮助,请点赞支持!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/23 1:35:55

Llama 4开源大模型:4000亿参数平民化部署实战

1. Llama 4开源革命:4000亿参数模型的平民化突破当Meta宣布Llama 4以完全免费的Apache 2.0许可证开源时,整个AI行业的地基发生了震动。这个拥有4000亿参数的庞然大物,不仅打破了商用大模型的技术壁垒,更关键的是它让普通开发者第一…

作者头像 李华
网站建设 2026/7/23 1:35:05

零基础入门AI:10个实战方法与避坑指南

1. 为什么普通人需要学习AI?在2023年,全球AI市场规模已经突破5000亿美元,麦肯锡最新报告显示,87%的企业正在将AI技术纳入业务流程。但更关键的是,AI不再只是科技公司的专利——它正在像当年的互联网一样,渗…

作者头像 李华
网站建设 2026/7/23 1:34:02

Tomcat生产环境配置优化与高可用实践

1. 生产环境Tomcat配置的核心考量在互联网企业的Java Web服务部署中,Tomcat作为轻量级应用服务器承担着关键角色。与开发环境不同,生产环境的配置需要兼顾性能、安全性和稳定性三大维度。我曾参与过某电商平台从测试环境到生产环境的迁移,当时…

作者头像 李华
网站建设 2026/7/23 1:28:38

VM虚拟机显卡去虚拟化实战:修改硬件ID与显存参数

1. VM虚拟机去虚拟化之显卡修改实战指南刚入行逆向分析那会儿,最头疼的就是虚拟机指纹被检测。有次在某电商平台爬数据,刚跑了两天脚本就被封号——后台直接识别出我用的VMware虚拟机。后来跟圈内大佬请教才知道,修改虚拟机硬件信息是反检测的…

作者头像 李华