优先用 TotalFreeSpace 计算百分比告警,检查 IsReady 防异常,用 PeriodicTimer 或 System.Threading.Timer 避免死等,报警阈值需按盘用途区分设置。

怎么用 DriveInfo 获取剩余空间(别直接除以 1024 就完事)
直接读 AvailableFreeSpace 是最常用做法,但单位是字节,人眼根本没法判断是否危险。更关键的是:NTFS 压缩、配额、卷影副本这些机制会让这个值和“用户实际能写入的空间”不一致——它只是当前可用字节数,不是“还能安全写多少”。
实操建议:
- 优先用
TotalFreeSpace(含系统保留空间)比AvailableFreeSpace更贴近真实告警场景 - 务必检查
IsReady,U 盘拔掉或光驱没盘时访问会抛IOException - 计算百分比时用
(double)drive.TotalFreeSpace / drive.TotalSize,别用整数除法,否则永远得 0 - 示例:
var drive = new DriveInfo("C:\");<br>if (drive.IsReady)<br> double freeRate = (double)drive.TotalFreeSpace / drive.TotalSize;
定时检查别用 Thread.Sleep 死等(尤其 Windows 服务里)
在后台长期运行时,用 Thread.Sleep(60000) 看似简单,但线程卡住、进程挂起、系统休眠都会让下一次检查严重延迟甚至永久丢失。.NET 6+ 推荐用 PeriodicTimer,老版本用 Timer + 手动防重入。
常见错误现象:Timer 回调里没加锁或没禁用重复触发,磁盘满时日志刷屏、发多条报警邮件。
实操建议:
- 用
System.Threading.Timer,构造时传TimeSpan.FromMinutes(5),回调里先Change(Timeout.Infinite, Timeout.Infinite)再干活,完事再Change下次 - 避免在回调里做耗时操作(如发邮件),只设标志位或投递到
Task.Run - 别把检查逻辑塞进 WinForms 的
Timer.Tick,UI 线程卡住会导致整个检查停摆
报警阈值不能写死 10%(不同盘用途差异极大)
C 盘剩 15GB 和 D 盘剩 15GB 完全是两回事。系统盘低于 20GB 很可能连 Windows Update 都失败;而存归档数据的 E 盘,5% 都未必需要告警。硬编码一个百分比,等于放弃运维合理性。
使用场景差异明显:
- 系统盘(C:):建议按绝对值 + 百分比双条件,例如 “
- 数据库数据盘:关注连续空闲簇大小(
GetDiskFreeSpaceEx不暴露这个,得 P/InvokeGetVolumeInformation) - 日志盘:更应监控文件数量增长速率,而非静态剩余空间
- 示例阈值配置:
new { Drive = "C:\", MinFreeGB = 10, MinFreePercent = 12 }<br>new { Drive = "D:\", MinFreeGB = 50, MinFreePercent = 5 }
发邮件报警前先确认 SMTP 配置能连通(别让磁盘满了还收不到通知)
很多实现把发邮件逻辑和磁盘检查耦合在一起,结果磁盘快满时,SMTP 连接超时或认证失败,报警无声无息消失。更糟的是,有些代码把异常吞掉还记个日志就完事,等于没告警。
性能与兼容性影响:
- .NET Core 3.1+ 默认禁用
SmtpClient(已标记 obsolete),必须改用MailKit或MimeKit - 别在每次检查都新建
SmtpClient实例,连接池复用能显著降低超时概率 - 务必在首次启动时做一次 SMTP 连通性测试,并记录结果;失败则立刻写本地日志,别等磁盘真满了才试
- 本地日志路径也得检查——如果所有盘都只剩 100MB,连日志都写不进去
真正难的从来不是读出那个数字,而是让告警在系统最脆弱的时候依然可靠抵达。磁盘空间监控里,最常被跳过的其实是“告警通道自身健康度验证”。










