C# 什么';这是';最佳';将流解析为结构或类的方法?
实际上,我正在使用.NETFramework3.5,所以我有所有这些很好的小功能,比如lambdas、linq等等 给定的是一个串行连接(或者更抽象地说,是一个流),您在其中接收一些数据,这些数据的格式如下:C# 什么';这是';最佳';将流解析为结构或类的方法?,c#,C#,实际上,我正在使用.NETFramework3.5,所以我有所有这些很好的小功能,比如lambdas、linq等等 给定的是一个串行连接(或者更抽象地说,是一个流),您在其中接收一些数据,这些数据的格式如下: struct Packet { byte STX UInt16 DataLength string Data byte CRC byte ETX } 使用传入数据的简单映射没有帮助,因为您不知道一个数据包将有多长,因为它写在结构中(数据长度) 所以
struct Packet
{
byte STX
UInt16 DataLength
string Data
byte CRC
byte ETX
}
使用传入数据的简单映射没有帮助,因为您不知道一个数据包将有多长,因为它写在结构中(数据长度)
所以我的第一个想法是按字节读取流并将其放入???。是的,这是下一个问题。在哪里存储第一个原始数据?进入一个简单的字节数组,最大可能长度(由于DataLength是一个UInt16加上其他字段的额外字节,因此将为65540字节)。或者我应该打开一个队列并填满所有传入的字节,或者可能存在另一个很好的可能性
让我们假设这些问题已经解决,并且我有某种本地缓冲区,它保存流中的所有原始字节。用给定的结构来解释它最好的方法是什么??只是执行某种for或foreach循环,或者存在一种更智能(性能更好)的方法(例如使用regex或linq)
致以最良好的祝愿,
Oliver我会将它们存储在字节数组中,然后从那里重新创建它们,这是一种快速而简单的方法
我将读取字节并用BitConverter、Encoding.UTF8.转换它们。我将它们存储在字节数组中,然后从那里重新创建它们,这是一种快速而简单的方法
我将读取字节并使用BitConverter、Encoding.UTF8..对其进行转换。总之,它归结为使用[Serializable]属性,您的操作完成了
看看这个,不管怎样,它归结为使用了[Serializable]属性,并且您的操作完成了 那么
struct Packet
{
public byte STX;
public UInt16 DataLength;
public string Data;
public byte CRC;
public byte ETX;
}
//Warning: Need to add error handling
class PacketReader
{
private BinaryReader _reader;
public PacketReader(Stream stream)
{
_reader = new BinaryReader(stream);
}
Packet ReadPacket()
{
var packet = new Packet()
{
STX = _reader.ReadByte(),
DataLength = _reader.ReadUInt16(),
Data = Encoding.ASCII.GetString(
_reader.ReadBytes(packet.DataLength)),
CRC = _reader.ReadByte(),
ETX = _reader.ReadByte()
};
return packet;
}
}
请注意:我并没有故意使用BinaryReader.ReadString(),因为它是为处理BinaryWriter.WriteString()生成的字符串而设计的。即使是长度前缀字符串,编码也有点不同。那么
struct Packet
{
public byte STX;
public UInt16 DataLength;
public string Data;
public byte CRC;
public byte ETX;
}
//Warning: Need to add error handling
class PacketReader
{
private BinaryReader _reader;
public PacketReader(Stream stream)
{
_reader = new BinaryReader(stream);
}
Packet ReadPacket()
{
var packet = new Packet()
{
STX = _reader.ReadByte(),
DataLength = _reader.ReadUInt16(),
Data = Encoding.ASCII.GetString(
_reader.ReadBytes(packet.DataLength)),
CRC = _reader.ReadByte(),
ETX = _reader.ReadByte()
};
return packet;
}
}
请注意:我并没有故意使用BinaryReader.ReadString(),因为它是为处理BinaryWriter.WriteString()生成的字符串而设计的。即使是长度前缀字符串,编码也有点不同。另一种可能的选择,利用C#的yield关键字:
public struct Packet
{
public byte STX;
public UInt16 DataLength;
public string Data;
public byte CRC;
public byte ETX;
}
public static class StreamExtensions
{
public IEnumerable<Packet> ToPacketStream(this Stream stream)
{
BinaryReader reader = new BinaryReader(stream);
while(reader.PeekChar() != -1) //Optionally change this to reflect your exit conditions
{
var packet = new Packet();
packet.STX = _reader.ReadByte();
packet.DataLength = _reader.ReadUInt16();
packet.Data = Encoding.ASCII.GetString(_reader.ReadBytes(packet.DataLength));
packet.CRC = _reader.ReadByte();
packet.ETX = _reader.ReadByte();
yield return packet;
}
}
}
//Usage
foreach(var packet in stream.ToPacketStream())
{
//Handle packet
}
公共结构数据包
{
公共字节STX;
公共UInt16数据长度;
公共字符串数据;
公共字节CRC;
公共字节ETX;
}
公共静态类StreamExtensions
{
公共IEnumerable ToPacketStream(此流)
{
BinaryReader=新的BinaryReader(流);
while(reader.PeekChar()!=-1)//可以选择更改此值以反映退出条件
{
var数据包=新数据包();
packet.STX=_reader.ReadByte();
packet.DataLength=_reader.ReadUInt16();
packet.Data=Encoding.ASCII.GetString(_reader.ReadBytes(packet.DataLength));
packet.CRC=_reader.ReadByte();
packet.ETX=_reader.ReadByte();
产生返回包;
}
}
}
//用法
foreach(stream.ToPacketStream()中的var数据包)
{
//句柄包
}
另一个可能的选择,利用C#的收益率关键字:
public struct Packet
{
public byte STX;
public UInt16 DataLength;
public string Data;
public byte CRC;
public byte ETX;
}
public static class StreamExtensions
{
public IEnumerable<Packet> ToPacketStream(this Stream stream)
{
BinaryReader reader = new BinaryReader(stream);
while(reader.PeekChar() != -1) //Optionally change this to reflect your exit conditions
{
var packet = new Packet();
packet.STX = _reader.ReadByte();
packet.DataLength = _reader.ReadUInt16();
packet.Data = Encoding.ASCII.GetString(_reader.ReadBytes(packet.DataLength));
packet.CRC = _reader.ReadByte();
packet.ETX = _reader.ReadByte();
yield return packet;
}
}
}
//Usage
foreach(var packet in stream.ToPacketStream())
{
//Handle packet
}
公共结构数据包
{
公共字节STX;
公共UInt16数据长度;
公共字符串数据;
公共字节CRC;
公共字节ETX;
}
公共静态类StreamExtensions
{
公共IEnumerable ToPacketStream(此流)
{
BinaryReader=新的BinaryReader(流);
while(reader.PeekChar()!=-1)//可以选择更改此值以反映退出条件
{
var数据包=新数据包();
packet.STX=_reader.ReadByte();
packet.DataLength=_reader.ReadUInt16();
packet.Data=Encoding.ASCII.GetString(_reader.ReadBytes(packet.DataLength));
packet.CRC=_reader.ReadByte();
packet.ETX=_reader.ReadByte();
产生返回包;
}
}
}
//用法
foreach(stream.ToPacketStream()中的var数据包)
{
//句柄包
}
抱歉,序列化不起作用,因为我只是数据的接收者,无法更改布局以使序列化工作。抱歉,序列化不起作用,因为我只是数据的接收者,无法更改布局以使序列化工作。我可能会添加IDisposable,也许可以称之为ReadPacket——但这是一个很好的答案,+1但为什么这里需要IDisposable?我没有使用任何非托管资源,为什么不让垃圾收集器替我做呢?“非托管资源”将是一个终结器。IDisposable是因为您正在封装/表示可IDisposable的其他内容—流和二进制读取器。您的Dispose()应该调用_reader.Dispose();看来是个好机会。如前所述,需要进行一些错误处理,但我想我会尝试一下。@Marc Gravell:该流最初不是我创建的,在我的类中关闭它会违反直觉。我可能会添加IDisposable,或者称之为ReadPacket-但这是一个很好的答案,+1但为什么这里需要IDisposable?我没有使用任何非托管资源,为什么不让垃圾收集器替我做呢?“非托管资源”将是一个终结器。IDisposable是因为您正在封装/表示可IDisposable的其他内容—流和二进制读取器。您的Dispose()应该调用_reader.Dispose();看来是个好机会。如前所述,需要进行一些错误处理,但我想我会尝试一下。@Marc Gravell:流最初不是我创建的