C# FileStream.BeginRead不';我好像再也回不来了
我正在使用异步读取带有c#的usb设备。我正在使用filestream来执行此操作。当我执行FileStream.BeginRead时。它似乎没有进行回调。这是什么问题 这是我的密码C# FileStream.BeginRead不';我好像再也回不来了,c#,usb,hid,C#,Usb,Hid,我正在使用异步读取带有c#的usb设备。我正在使用filestream来执行此操作。当我执行FileStream.BeginRead时。它似乎没有进行回调。这是什么问题 这是我的密码 /// <summary> /// Initialises the device /// </summary> /// <param name="strPath">Path to the device</param> private
/// <summary>
/// Initialises the device
/// </summary>
/// <param name="strPath">Path to the device</param>
private void Initialise(String strPath)
{
// Create the file from the device path
SafeHandle = CreateFile(strPath, FileAccess.ReadWrite, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open,
EFileAttributes.Overlapped, IntPtr.Zero);
if (SafeHandle != null) // if the open worked...
{
IntPtr lpData;
if (HidD_GetPreparsedData(SafeHandle, out lpData))
// get windows to read the device data into an internal buffer
{
try
{
HidCaps hidCaps;
HidP_GetCaps(lpData, out hidCaps); // extract the device capabilities from the internal buffer
InputReportLength = hidCaps.InputReportByteLength; // get the input...
OutputReportLength = hidCaps.OutputReportByteLength; // ... and output report lengths
FileStream = new FileStream((SafeFileHandle) SafeHandle, FileAccess.ReadWrite, InputReportLength,
true); // wrap the file handle in a .Net file stream
BeginAsyncRead(); // kick off the first asynchronous read
}
finally
{
HidD_FreePreparsedData(ref lpData);
// before we quit the function, we must free the internal buffer reserved in GetPreparsedData
}
}
else // GetPreparsedData failed? Chuck an exception
throw HidDeviceException.GenerateWithWinError("GetPreparsedData failed");
}
else // File open failed? Chuck an exception
{
SafeHandle = null;
throw HidDeviceException.GenerateWithWinError("Failed to create device file");
}
}
//
///初始化设备
///
///设备的路径
私有void初始化(字符串strPath)
{
//从设备路径创建文件
SafeHandle=CreateFile(strPath,FileAccess.ReadWrite,FileShare.ReadWrite,IntPtr.Zero,FileMode.Open,
eFileAttribute.Overlapped,IntPtr.Zero);
if(SafeHandle!=null)//如果打开的文件有效。。。
{
IntPtr-lpData;
if(HidD_GetPreparsedData(安全句柄,输出lpData))
//让windows将设备数据读入内部缓冲区
{
尝试
{
HidCaps HidCaps;
HidP_GetCaps(lpData,out-hidCaps);//从内部缓冲区提取设备功能
InputReportLength=hidCaps.InputReportByTeleLength;//获取输入。。。
OutputReportLength=hidCaps.OutputReportByTeleLength;//…和输出报告长度
FileStream=新文件流((SafeFileHandle)SafeHandle,FileAccess.ReadWrite,InputReportLength,
true);//将文件句柄包装到.Net文件流中
BeginAsyncRead();//开始第一次异步读取
}
最后
{
HidD_FreePreparsedData(参考lpData);
//在退出函数之前,必须释放GetPreparsedData中保留的内部缓冲区
}
}
else//GetPreparsedData失败?出现异常
抛出HidDeviceException.GenerateWithInError(“GetPreparsedData失败”);
}
否则//文件打开失败?出现异常
{
SafeHandle=null;
抛出HidDeviceException.GenerateWithInError(“未能创建设备文件”);
}
}
这是回调
/// <summary>
/// Kicks off an asynchronous read which completes when data is read or when the device
/// is disconnected. Uses a callback.
/// </summary>
private void BeginAsyncRead()
{
Byte[] buffer = new Byte[InputReportLength];
// put the buff we used to receive the stuff as the async state then we can get at it when the read completes
FileStream.BeginRead(buffer, 0, InputReportLength, ReadCompleted, buffer);
}
//
///启动异步读取,该读取在读取数据或设备启动时完成
///已断开连接。使用回调。
///
私有无效开始同步()
{
字节[]缓冲区=新字节[InputReportLength];
//将我们用来接收内容的buff作为异步状态,然后我们可以在读取完成时获得它
BeginRead(缓冲区,0,InputReportLength,ReadCompleted,缓冲区);
}
这是我的回电
/// <summary>
/// Callback for above. Care with this as it will be called on the background thread from the async read
/// </summary>
/// <param name="iResult">Async result parameter</param>
private void ReadCompleted(IAsyncResult iResult)
{
Byte[] buffer = (Byte[])iResult.AsyncState; // retrieve the read buffer
try
{
FileStream.EndRead(iResult); // call end read : this throws any exceptions that happened during the read
try
{
HandleDataReceived(buffer); // pass the new input report on to the higher level handler
}
finally
{
BeginAsyncRead(); // when all that is done, kick off another read for the next report
}
}
catch (IOException) // if we got an IO exception, the device was removed
{
HandleDeviceRemoved();
if (OnDeviceRemoved != null)
OnDeviceRemoved(this, new EventArgs());
Dispose();
}
}
//
///以上内容的回调。注意这一点,因为它将从异步读取在后台线程上调用
///
///异步结果参数
私有void ReadCompleted(IAsyncResult-iResult)
{
字节[]缓冲区=(字节[])iResult.AsyncState;//检索读取缓冲区
尝试
{
FileStream.EndRead(iResult);//调用end read:这会引发读取过程中发生的任何异常
尝试
{
HandleDataReceived(buffer);//将新的输入报告传递给更高级别的处理程序
}
最后
{
BeginAsyncRead();//完成所有操作后,开始阅读下一个报告
}
}
catch(IOException)//如果我们得到了一个IO异常,那么设备就被删除了
{
HandleDeviceMoved();
如果(OnDeviceRemoved!=null)
OnDeviceRemoved(这是新的EventArgs());
处置();
}
}
更新我想知道我在devicePath中是否做错了
/// <summary>
/// Helper method to return the device path given a DeviceInterfaceData structure and an InfoSet handle.
/// Used in 'FindDevice' so check that method out to see how to get an InfoSet handle and a DeviceInterfaceData.
/// </summary>
/// <param name="hInfoSet">Handle to the InfoSet</param>
/// <param name="oInterface">DeviceInterfaceData structure</param>
/// <returns>The device path or null if there was some problem</returns>
private static string GetDevicePath(IntPtr hInfoSet, ref DeviceInterfaceData oInterface)
{
uint nRequiredSize = 0;
// Get the device interface details
if (!SetupDiGetDeviceInterfaceDetail(hInfoSet, ref oInterface, IntPtr.Zero, 0, ref nRequiredSize, IntPtr.Zero))
{
DeviceInterfaceDetailData oDetail = new DeviceInterfaceDetailData();
oDetail.Size = Marshal.SizeOf(typeof(IntPtr)) == 4 ? 8 : 5; // check if is a 64 bit
if (SetupDiGetDeviceInterfaceDetail(hInfoSet, ref oInterface, ref oDetail, nRequiredSize, ref nRequiredSize, IntPtr.Zero))
{
return oDetail.DevicePath;
}
}
return null;
}
//
///方法返回给定DeviceInterface数据结构和信息集句柄的设备路径。
///在“FindDevice”中使用,请检查该方法以了解如何获取信息集句柄和DeviceInterfaceData。
///
///信息集的句柄
///DeviceInterface数据结构
///如果出现问题,请输入设备路径或null
私有静态字符串GetDevicePath(IntPtr hInfoSet,ref DeviceInterfaceData oInterface)
{
uint nRequiredSize=0;
//获取设备接口的详细信息
if(!SetupDiGetDeviceInterfaceDetail(hInfoSet,ref oInterface,IntPtr.Zero,0,ref nRequiredSize,IntPtr.Zero))
{
DeviceInterfaceDetailData oDetail=新的DeviceInterfaceDetailData();
oDetail.Size=Marshal.SizeOf(typeof(IntPtr))==4?8:5;//检查是否为64位
if(SetupDiGetDeviceInterfaceDetail(hInfoSet、ref-oInterface、ref-oDetail、nRequiredSize、ref-nRequiredSize、IntPtr.Zero))
{
返回oDetail.DevicePath;
}
}
返回null;
}
所以你可以看看我写的一个快速示例
class Program
{
static Byte[] buffer = new Byte[1024];
public static void Main()
{
FileStream fileStream = File.OpenRead("data.txt");
fileStream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(FileReadCallback), fileStream);
Console.ReadLine();
}
public static void FileReadCallback(IAsyncResult result)
{
FileStream fileStream = (FileStream)result.AsyncState;
fileStream.EndRead(result);
foreach (Byte b in buffer)
Console.Write((Char)b);
}
}
尽管这种方法有效,但它是非常古老的c++风格。写这样的东西要容易得多:
public static void Main()
{
using (FileStream fileStream = File.OpenRead("data.txt"))
using (StreamReader reader = new StreamReader(fileStream))
{
// This will read a single line of text
String line = reader.ReadLine();
}
}
然后使用System.Threading.Tasks.Task
类在另一个线程上执行它,如下所示:
public static void Main()
{
Task.Run(ThisWillExecuteOnAnotherThread);
}
public static void ThisWillExecuteOnAnotherThread()
{
using (FileStream fileStream = File.OpenRead("data.txt"))
using (StreamReader reader = new StreamReader(fileStream))
{
// This will read a single line of text
String line = reader.ReadLine();
}
}
我个人认为这种风格要干净得多
更新
因此,此设置在我的机器上运行良好:
class Program
{
static byte[] buffer;
static int InputReportLength = 1024;
static FileStream fileStream;
public static void Main()
{
BeginAsyncRead();
}
private static void BeginAsyncRead()
{
buffer = new Byte[InputReportLength];
fileStream = File.OpenRead("Data.txt");
// put the buff we used to receive the stuff as the async state then we can get at it when the read completes
fileStream.BeginRead(buffer, 0, InputReportLength, ReadCompleted, buffer);
}
private static void ReadCompleted(IAsyncResult iResult)
{
Byte[] buffer = (Byte[])iResult.AsyncState; // retrieve the read buffer
}
}
我建议你不要这样做:
FileStream FileStream = ....
一般来说,你应该“PascalCase”你的类名和“camelCase”你的变量。另外,作为一个一般性建议,代码的结构方式要求您在页面上进行多次跳转,这将使您在以后需要再次查看代码时很难进行维护。尽量使事情保持在一起。是否将回调作为参数添加到方法调用中,如本例所示:
public void LoadFile(string fileName)
{
currentFileStream = new FileStream("Foo.txt", FileMode.Open, FileAccess.Read, FileShare.Read, 1024 * 8, true);
buffer = new byte[currentFileStream.Length];
currentFileStream.BeginRead(buffer, 0, buffer.Length, FileReadComplete, currentFileStream);
}
private void FileReadComplete(IAsyncResult result)
{
// do your code
}
显示您的代码。然后其他人可以帮助您。ReadCompleted在哪里完成?这才是真正的关键功能。另外,不要将缓冲区作为最终argu发送
// Create a synchronization object that gets
// signaled when verification is complete.
ManualResetEvent manualEvent = new ManualResetEvent(false);
// Create random data to write to the file.
byte[] writeArray = new byte[100000];
new Random().NextBytes(writeArray);
FileStream fStream =
new FileStream("Test#@@#.dat", FileMode.Create,
FileAccess.ReadWrite, FileShare.None, 4096, true);
// Check that the FileStream was opened asynchronously.
Console.WriteLine("fStream was {0}opened asynchronously.",
fStream.IsAsync ? "" : "not ");
// Asynchronously write to the file.
IAsyncResult asyncResult = fStream.BeginWrite(
writeArray, 0, writeArray.Length,
new AsyncCallback(EndWriteCallback),
new State(fStream, writeArray, manualEvent));
// Concurrently do other work and then wait
// for the data to be written and verified.
manualEvent.WaitOne(5000, false);