USB拷贝文件中途设备断开时try catch捕获异常失败问题求助
问题解答
异常未捕获的核心原因
你的问题确实和当前Task.Run+Wait()的使用方式有关,核心是Task的异常传播机制:
- 当通过
Task.Run提交的委托内部抛出未处理异常时,异常会被封装到AggregateException对象中,直到你调用Wait()、Result或者访问Exception属性的时候才会向外抛出 - 如果你外层的try catch只捕获了
IOException等具体业务异常,没有捕获AggregateException,就会导致异常漏触发程序崩溃 - 部分情况下USB设备突然断开时,底层IO可能抛出非托管异常,如果没有做全局异常兜底也会导致崩溃
修复方案
方案1:保留Wait写法,补充AggregateException捕获
try { var t = Task.Run(() => { // 拷贝前先校验源文件/USB设备是否存在,提前拦截异常 if(!File.Exists(s) || !Directory.Exists(Path.GetDirectoryName(destFileBU))) { throw new DriveNotFoundException("存储设备已断开"); } System.IO.File.Copy(s, destFileBU, overwrite: true); }); t.Wait(); } catch (AggregateException ae) { // 遍历处理所有内部异常 ae.Handle(ex => { if (ex is IOException || ex is DriveNotFoundException) { // 这里加你的业务处理逻辑,比如记录日志、提示用户 Console.WriteLine($"拷贝中断:设备已断开或文件不可访问,{ex.Message}"); return true; // 标记该异常已处理 } return false; // 其他异常继续向外抛出 }); } catch (Exception ex) { // 全局兜底捕获 Console.WriteLine($"未预期错误:{ex.Message}"); }
方案2(更推荐):改用async/await语法,自动解包异常
await会自动拆分AggregateException,直接抛出内部的实际异常,捕获逻辑更简洁:
// 注意调用该逻辑的外层方法需要声明为 async Task/async Task<T> try { await Task.Run(() => { if(!File.Exists(s) || !Directory.Exists(Path.GetDirectoryName(destFileBU))) { throw new DriveNotFoundException("存储设备已断开"); } System.IO.File.Copy(s, destFileBU, overwrite: true); }); } catch (IOException ex) { Console.WriteLine($"拷贝中断:设备已断开或文件不可访问,{ex.Message}"); } catch (Exception ex) { Console.WriteLine($"未预期错误:{ex.Message}"); }
适配消防员便携场景的额外优化建议
- 大文件不要直接用
File.Copy,改成流式分段拷贝,每写入一段就校验完整性,设备断开后下次插入可直接续传,避免重复拷贝 - 拷贝过程中增加定时检测USB设备挂载状态的逻辑,检测到设备断开后主动终止拷贝,不用等待IO异常抛出
- 增加全局未捕获异常处理(WPF/WinForm/控制台都有对应的全局异常事件),避免极端情况导致程序直接崩溃
内容的提问来源于stack exchange,提问作者Josef
相关产品推荐
相关产品推荐

