C#检测USB驱动器是否可移除及安全拔出方案咨询
检查USB驱动器是否正被使用或可安全拔出的可行方案
针对你遇到的USB文件写入未完成但弹窗提前提示、用户过早拔出的问题,以及对File.Open()+try-catch方案的不满,以下是几种更可靠的解决思路:
1. 强制刷新文件写入缓冲区,确保数据落地
在文件复制/写入操作完成后,必须强制将操作系统缓存中的数据刷入磁盘,避免依赖系统自动刷新导致的"写入完成"误判:
// 示例:复制文件后强制刷新到物理磁盘 using (var sourceStream = new FileStream(sourcePath, FileMode.Open, FileAccess.Read)) using (var destStream = new FileStream(destPath, FileMode.Create, FileAccess.Write)) { await sourceStream.CopyToAsync(destStream); destStream.Flush(true); // true表示跳过系统缓存,直接刷新到磁盘 } // 额外验证:对比源文件与目标文件大小,确认写入完整 var sourceSize = new FileInfo(sourcePath).Length; var destSize = new FileInfo(destPath).Length; if (sourceSize != destSize) { // 写入未完成,执行重试或提示逻辑 }
2. 使用Windows系统API检查设备可弹出状态
Windows提供了设备管理原生API,可直接查询USB驱动器的锁定状态,这是判断是否可安全弹出的最权威方式。核心调用CM_Request_Device_Eject函数:
[DllImport("setupapi.dll", SetLastError = true)] private static extern bool CM_Request_Device_Eject(IntPtr hDevice, out IntPtr pRebootRequired); // 示例:传入USB设备句柄,判断是否可安全弹出 public bool IsUsbSafeToEject(IntPtr deviceHandle) { IntPtr rebootRequired; var result = CM_Request_Device_Eject(deviceHandle, out rebootRequired); // 返回true表示设备无占用,可安全弹出;返回false则设备被锁定 return result; }
注意:需先通过SetupDiGetClassDevs等API枚举设备,获取目标USB驱动器对应的设备句柄。
3. 监控文件系统写入稳定状态
通过FileSystemWatcher监控USB目录的文件变化,结合文件锁定状态判断写入是否真正完成:
var watcher = new FileSystemWatcher(@"D:\") // 替换为你的USB驱动器路径 { NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size, Filter = "*.*" }; watcher.Changed += (sender, e) => { // 等待文件状态稳定(避免写入过程中多次触发变更) Task.Delay(1000).ContinueWith(_ => { try { // 尝试独占打开文件,无异常则说明写入完成且无进程占用 using (var stream = File.Open(e.FullPath, FileMode.Open, FileAccess.ReadWrite, FileShare.None)) { Console.WriteLine($"文件 {e.FullPath} 已完成写入"); } } catch (IOException) { // 文件仍被占用,写入未完成 } }); }; watcher.EnableRaisingEvents = true;
为什么File.Open()+try-catch不够可靠?
这种方式仅能判断文件是否被进程锁定,无法检测系统缓存中未落地的数据——即使文件能被打开,缓存中的数据可能还未写入磁盘,此时拔出U盘依然会导致文件损坏。
内容的提问来源于stack exchange,提问作者alexisL
相关产品推荐
相关产品推荐

