C#检测U盘需重写WndProc监听WM_DEVICECHANGE消息,解析DEV_BROADCAST_VOLUME获取盘符,结合DriveInfo判断Removable且IsReady;读写时用FileStream加WriteThrough选项,捕获共享冲突与设备未就绪异常,并延迟重试。

如何用 C# 检测 U 盘插入和拔出事件
Windows 不会主动通知 .NET 应用某个 USB 设备是 U 盘,但可以通过 WM_DEVICECHANGE 消息捕获设备增减,并结合 DriveInfo 和设备类型判断是否为可移动驱动器。关键不是“识别U盘”,而是“识别可移动且就绪的卷”。
- 必须重写窗体的
WndProc方法监听WM_DEVICECHANGE(值为0x0219),仅靠轮询DriveInfo.GetDrives()效率低且有延迟 - 收到
DBT_DEVICEARRIVAL后,需调用Marshal.PtrToStringAuto解析lParam中的DEV_BROADCAST_VOLUME结构,提取dbcv_unitmask得到盘符位掩码 - 对每个置位的盘符(如 bit 0 → A:,bit 1 → B:),构造
new DriveInfo("D:\"),检查DriveType == DriveType.Removable且IsReady == true - 注意:部分读卡器、手机 MTP 模式、加密U盘可能报告为
DriveType.Fixed或根本不出现在GetDrives()中——这不是代码问题,是 Windows 驱动层行为
如何安全读写 U 盘文件(避免“设备正忙”错误)
直接对 "E:\data.txt" 调用 File.WriteAllText 极易失败,因为 U 盘可能被系统缓存、杀毒软件扫描或资源管理器预览占用。核心是绕过缓存 + 捕获具体拒绝原因。
- 写入优先用
FileStream手动控制,设置FileOptions.WriteThrough | FileOptions.SequentialScan,避免系统缓存干扰 - 打开前先尝试
File.Open(path, FileMode.Open, FileAccess.Read, FileShare.None),若抛出IOException且HResult == -2147024864(即ERROR_SHARING_VIOLATION),说明文件被占用 - 读取时若遇到
UnauthorizedAccessException,大概率是 U 盘启用了 BitLocker 或设置了只读属性,需检查new DriveInfo("F:\").IsReadOnly - 永远不要在 UI 线程做耗时 IO;用
await Task.Run(() => File.ReadAllBytes(path))避免界面假死
为什么 DriveInfo.IsReady 返回 true 却仍打不开文件
IsReady 只表示驱动器有盘符、能响应基本查询,不代表文件系统可用或硬件稳定。常见于劣质 U 盘、USB 延长线供电不足、或 Windows Fast Startup 导致残留锁。
- 典型错误信息:
System.IO.IOException: The device is not ready.—— 此时DriveInfo.IsReady可能刚由false变为true,但底层尚未完成初始化 - 实操建议:检测到新驱动器后,等待 500ms,再循环尝试
Directory.GetFiles(drive.RootDirectory.FullName, "*.*", SearchOption.TopDirectoryOnly),最多重试 3 次 - 若始终失败,用
Win32_VolumeWMI 类查DriveLetter和Capacity,比DriveInfo更底层可靠(需引用System.Management)
跨平台方案?别指望 .NET Core 的 DriveInfo
.NET 6+ 的 DriveInfo.GetDrives() 在 Linux/macOS 下返回空数组或抛异常,因为这些系统没有“盘符”概念。U 盘在 Linux 是 /media/username/XXXX,在 macOS 是 /Volumes/XXXX。
- Linux 下可用
DBus监听org.freedesktop.UDisks2.Device的Added/Removed信号(需Microsoft.DBus包) - macOS 推荐轮询
/Volumes目录,用FileSystemWatcher监控其Created/Deleted事件(注意:不触发重命名) - 纯跨平台业务逻辑应避免硬编码盘符,改用配置文件或用户选择路径;
DriveInfo仅作为 Windows 快速入口
真正麻烦的从来不是“怎么读写”,而是“怎么确认此刻能读写”。硬件抽象层之下,永远有驱动、固件、电源和 Windows 自己的缓存策略在悄悄作祟。


















