将流解析为结构或类的“最佳”方法是什么?

时间:2009-02-12 07:39:01

标签: c#

实际上我正在使用.Net Framework 3.5,所以我拥有所有这些不错的小功能,如lambdas,linq等。

给定的是一个串行连接(或更抽象的:流),您可以在其中接收一些数据,其格式如下:

struct Packet
{
    byte STX
    UInt16 DataLength
    string Data
    byte CRC
    byte ETX
}

使用传入数据的简单映射并没有帮助,因为您实际上并不知道一个数据包将持续多长时间,因为它是在结构中写入的(DataLength)。

所以我的第一个想法是按字节读取流并将其放入???中。是的,这是下一个问题。在哪里存储这个第一个原始数据?进入一个简单的字节数组,具有最大可能的长度(即65540字节,因为DataLength是一个UInt16加上来自其他字段的附加字节)。或者我应该打开一个队列并将其填满所有传入的字节或者可能存在另一个很好的可能性吗?

让我们假设这些问题被清除,我有一些本地缓冲区,它保存流中的所有原始字节。给定结构解释它的最好方法是什么?只是做某种for-or foreach-loop或存在更聪明(性能更好)的方式(例如使用正则表达式或linq)?

祝你好运, 奥利弗

4 个答案:

答案 0 :(得分:5)

怎么样......

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()生成的字符串进行操作。即使它的长度为前缀字符串,编码也有点不同。

答案 1 :(得分:0)

我会将它们存储在一个字节数组中并从那里重新创建它,这是一种快速而简单的方法!

我会读取字节并使用BitConverter转换它们,Encoding.UTF8 ..

答案 2 :(得分:0)

检查一下,无论如何它归结为使用[Serializable]属性,并完成了 http://www.ondotnet.com/pub/a/dotnet/2002/08/26/serialization.html

答案 3 :(得分:0)

另一个可能的选择,使用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
}