C#计算文件夹大小时点击C盘出现7-8秒应用卡顿问题求助
问题根因
当前实现存在两个核心问题直接导致点击C盘时应用冻结:
- 文件夹大小计算逻辑同步运行在UI线程:
FolderModel的构造函数由UI线程触发执行,你在构造函数内直接调用阻塞式的目录遍历逻辑,会直接卡住UI消息循环,直到全盘遍历完成才会恢复响应 - 全量目录遍历效率极低:
GetDirectorySize使用SearchOption.AllDirectories遍历所有子目录,C盘默认存在海量系统文件、受权限保护的隐藏目录(比如System Volume Information、Windows系统目录、用户AppData目录等),文件数量通常是普通数据盘的数倍,遍历耗时自然达到7-8秒甚至更久
排查验证思路
- 给
GetDirectorySize方法增加耗时、遍历文件数日志,确认阻塞是否由遍历C盘的高耗时导致 - 点击C盘时查看任务管理器中应用的CPU、磁盘IO占用,确认是否处于满负载遍历状态
- 单独测试遍历C盘下不同子目录的耗时,定位是否是特定系统目录的权限异常、大量小文件拖慢了整体速度
解决方案
1. 把同步计算改成异步非阻塞计算
不要在FolderModel构造函数中同步计算大小,构造时先显示*计算中...*占位符,后台异步计算完成后再更新UI:
// 改造示例,基于WPF的INotifyPropertyChanged实现 public string FolderSize { get => _folderSize; set { _folderSize = value; OnPropertyChanged(); } } private string _folderSize = "计算中..."; public FolderModel(string folderPath) { // 原有初始化逻辑保留 FolderInfo = new DirectoryInfo(folderPath); _folderName = FolderInfo.Name; _folderPath = folderPath; this.Children = new ObservableCollection<FolderModel>(); // 异步启动大小计算,不阻塞构造函数和UI线程 _ = CalculateFolderSizeAsync(folderPath); } private async Task CalculateFolderSizeAsync(string folderPath) { long totalSize = await Task.Run(() => GetDirectorySize(folderPath)); // 计算完成后切回UI线程更新显示 Application.Current.Dispatcher.Invoke(() => { FolderSize = CalculatorSize(totalSize); }); }
2. 优化目录遍历逻辑降低耗时
- 取消
SearchOption.AllDirectories全量遍历,改成按需层级计算:默认只统计当前目录第一层的文件大小,子目录大小等用户点击展开对应节点时再计算,不需要打开C盘就遍历全盘 - 增加系统目录过滤:默认跳过
System Volume Information、$Recycle.Bin、Windows、Program Files等权限受限的系统目录,避免无意义的权限异常和遍历消耗 - 遍历前判断目录属性,标记为
Hidden+System的目录默认跳过,减少无效遍历
3. 增加缓存机制
将已经计算完成的文件夹大小存入本地缓存,下次访问同一个目录时直接读取缓存结果,不需要重复遍历,仅监听目录文件变更事件,目录有修改时才触发重新计算。
4. 优化异常处理
你当前代码直接吞掉了所有异常,建议增加日志记录访问失败的目录,方便后续调整过滤规则,也能及时发现潜在的遍历异常。
内容的提问来源于stack exchange,提问作者user16741817
相关产品推荐
相关产品推荐

