F#读取Dualshock4时FileStream.ReadAsync失败但同步Read可正常运行
问题原因
- FileStream异步模式未显式启用:虽然调用
File.OpenHandle时指定了FileOptions.Asynchronous,但使用FileStream(SafeFileHandle, FileAccess)重载构造实例时,默认useAsync参数为false,此时FileStream会用同步IO逻辑模拟异步操作,针对HID这类非磁盘类特殊字符设备时,会触发Windows内核层的参数校验错误。 - 缓冲策略适配缺陷:.NET6默认的
BufferedFileStreamStrategy对非可寻的字符设备异步读取的兼容性存在问题,内部缓冲逻辑会额外修改IO请求参数,导致HID驱动拒绝请求,你遇到的报错堆栈中的BufferedFileStreamStrategy.<ReadFromNonSeekableAsync>d__38.MoveNext()也印证了这一点。
修复方案
修改FileStream构造逻辑,显式启用异步模式、禁用内部缓冲即可,修正后的完整代码如下:
module Example = let ds4ReadBufSize = 64 let read device = let buffer = Array.zeroCreate ds4ReadBufSize async { use file = File.OpenHandle(device, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite, FileOptions.Asynchronous ||| FileOptions.SequentialScan) // 显式指定禁用内部缓冲、启用异步模式 use fileStream = new FileStream(file, FileAccess.Read, bufferSize: 0, useAsync: true) let! d = fileStream.ReadAsync(buffer, 0, buffer.Length) |> Async.AwaitTask printfn "%d" d // 同时修正原代码的变量名笔误,原代码错误引用了未定义的read变量 }
如果修改后仍有异常,可以移除File.OpenHandle参数中的FileOptions.SequentialScan,该参数是针对磁盘文件顺序读取做的优化,对HID设备没有实际作用,反而可能干扰IO请求参数。
补充说明:如果后续适配其他HID设备,建议先调用Windows HID原生API获取设备的实际输入报告长度作为缓冲区大小,避免因缓冲区长度不匹配触发同类参数错误。
内容的提问来源于stack exchange,提问作者Aldo Stracquadanio
相关产品推荐
相关产品推荐

