我开发了一个监听串口的小程序。我的程序正在接收数据。问题是,它没有以所需的格式(一个字符串)显示它。我的程序接收的数据有两个字符串,例如:
ID:34242 State:NY
zip :12345 StreetType:Ave
它由 block 显示,一些数据被传递到下一行:
ID:34242
State:N
Y Zip:12
345 Street
Type:Ave
我已经使用 SerialDataReceive 事件处理程序来接收我的数据,它看起来像这样:
private static void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
SerialPort spL = (SerialPort) sender;
int bufSize = 20;
Byte[] dataBuffer = new Byte[bufSize];
Console.WriteLine("Data Received at"+DateTime.Now);
Console.WriteLine(spL.Read(dataBuffer, 0, bufSize));
string s = System.Text.ASCIIEncoding.ASCII.GetString(dataBuffer);
Console.WriteLine(s);
}
如您所见,我将字节检索到缓冲区中,创建一个字节数组来保存数据并使用 ASCII 编码将字节转换为字符串。我尝试使用 ReadLine(),但我的数据没有使用该函数显示。有谁知道将数据解析和格式化为一个字符串的任何其他方法?
最佳答案
问题是,正如您可能已经猜到的那样,一旦通过串行端口接收到数据,就会引发事件 DataReceived。那里可能没有完整的记录; SerialPort 对象不知道什么是您认为“足够”的数据是重要的或可行的。
通常的解决方案是维护接收数据的另一个“缓冲区”,其中包含您认为不完整的任何数据。当数据通过端口进入并且您的事件触发时,它应该首先获取缓冲区中的内容并将其附加到您已经收到的内容中。然后,您应该从这个数据缓冲区的开头开始检查接收到的数据,寻找对您有意义的已知数据原子“ block ”模式;例如,假设您收到的第一件事是 "ID: 12"
。您将其放入缓冲区,然后扫描缓冲区以查找由正则表达式 "ID:\d*? "
定义的模式。因为尾随空格不存在于您的缓冲区中,您的模式无法找到任何有意义的内容,因此您现在知道您没有收到完整的消息。
然后,在下一次引发 DataReceived 事件时,您将 "453 Sta"
从串行缓冲区中拉出。您将它附加到您已有的内容上并获得 "ID:12453 Sta"
,当您应用正则表达式时,您将获得匹配项“ID: 12345”。您将其传递给进一步处理的方法(可能显示到控制台),并从缓冲区的前面删除相同的字符串,留下“Sta”。再次扫描你没有发现任何其他感兴趣的东西,所以你留下你拥有的,并且循环重复 aws 数据继续进来。显然,你将测试更多的模式,而不仅仅是 ID 模式;您可以搜索您希望收到的整个“字符串”,例如 "ID:\d*? State:\w{2} "
。您甚至可以将数据保存在缓冲区中,直到您拥有两个字符串作为记录:"ID:\d*?State:\w{2} Zip:\d{5} StreetType:\w*?"
。
无论哪种方式,您都需要确定接收到的数据是可靠的“固定长度”(意味着特定类型的每个字符串将始终具有相同数量的字节或字符),还是可靠地“定界”(这意味着会有一些字符或字符组合始终分隔数据的重要元素)。如果这些都不适用,则可能很难将数据解析为单字段 block 。
这是一个基于您已有的示例:
private static StringBuilder receiveBuffer = new StringBuilder();
private static void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
SerialPort spL = (SerialPort) sender;
int bufSize = 20;
Byte[] dataBuffer = new Byte[bufSize];
Console.WriteLine("Data Received at"+DateTime.Now);
Console.WriteLine(spL.Read(dataBuffer, 0, bufSize));
string s = System.Text.ASCIIEncoding.ASCII.GetString(dataBuffer);
//here's the difference; append what you have to the buffer, then check it front-to-back
//for known patterns indicating fields
receiveBuffer.Append(s);
var regex = new Regex(@"(ID:\d*? State:\w{2} Zip:\d{5} StreetType:\w*? )");
Match match;
do{
match = regex.Match(receiveBuffer.ToString());
if(match.Success)
{
//"Process" the significant chunk of data
Console.WriteLine(match.Captures[0].Value);
//remove what we've processed from the StringBuilder.
receiveBuffer.Remove(match.Captures[0].Index, match.Captures[0].Length);
}
} while (match.Success);
}
关于c# - 从串口解析/格式化数据 - C#,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9505197/