USB打印机场景下FileStream.Dispose抛UnauthorizedAccessException的处理
USB打印设备Dispose异常处理及替代方案
一、用try/catch包裹Dispose调用的可行性
完全可以这么做,但要注意只捕获特定的UnauthorizedAccessException,别笼统捕获所有异常,避免掩盖其他潜在问题。修改后的Disconnect方法如下:
protected void Disconnect() { if (_printerStream != null) { try { _printerStream.Dispose(); } catch (UnauthorizedAccessException) { // 设备已断开,该异常属于预期情况,直接忽略 } finally { _printerStream = null; } } _printerHandle?.Dispose(); _printerHandle = null; }
设备插拔后旧句柄失效,FileStream.Dispose内部会尝试执行文件系统相关的清理操作,这些操作在无效句柄下会触发权限异常,捕获该特定异常即可,不会影响后续的句柄释放和资源清理。
二、更优的USB I/O实现方式
FileStream本质是为文件系统设计的封装,用来适配USB打印设备句柄确实存在兼容性问题,更推荐以下两种方案:
1. 直接基于SafeHandle调用Win32 API
跳过FileStream的封装,直接用ReadFile/WriteFile等Win32 API读写数据,释放资源时直接调用SafeHandle的Dispose(内部会调用CloseHandle,这是USB设备句柄的标准释放方式),完全避免FileStream带来的异常。
示例代码框架:
using System.ComponentModel; using System.Runtime.InteropServices; // 导入Win32 API [DllImport("kernel32.dll", SetLastError = true)] private static extern bool ReadFile(SafeHandle hFile, byte[] lpBuffer, uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, IntPtr lpOverlapped); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool WriteFile(SafeHandle hFile, byte[] lpBuffer, uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten, IntPtr lpOverlapped); private SafeHandle _printerHandle; public void Connect() { Disconnect(); _printerHandle = UsbPrinterResolver.OpenUSBPrinter(ConnectionString); } protected void Disconnect() { _printerHandle?.Dispose(); _printerHandle = null; } // 读数据示例 public int ReadPrinterData(byte[] buffer) { if (_printerHandle == null || _printerHandle.IsInvalid) throw new InvalidOperationException("打印机未连接"); if (ReadFile(_printerHandle, buffer, (uint)buffer.Length, out uint bytesRead, IntPtr.Zero)) return (int)bytesRead; throw new Win32Exception(Marshal.GetLastWin32Error()); } // 写数据示例 public void WritePrinterData(byte[] data) { if (_printerHandle == null || _printerHandle.IsInvalid) throw new InvalidOperationException("打印机未连接"); if (!WriteFile(_printerHandle, data, (uint)data.Length, out _, IntPtr.Zero)) throw new Win32Exception(Marshal.GetLastWin32Error()); }
2. 使用专门的USB通信库
比如LibUsbDotNet这类针对USB设备开发的专用库,它对USB设备的连接、断开、读写操作都做了针对性优化,比手动调用Win32 API更便捷,也能更好处理设备插拔后的状态变化,稳定性更高。
内容的提问来源于stack exchange,提问作者Ernis
相关产品推荐
相关产品推荐

