从字节数组读取行(不将字节数组转换为字符串)

时间:2009-01-29 16:50:55

标签: c# .net bytearray networkstream

我有一个从NetworkStream读取的字节数组。前两个字节表示后面的数据包的长度,然后将数据包读入该长度的字节数组。我需要从NetworkStream / byte数组中读取的数据有几个字符串,即由新行字符终止的可变长度数据,以及一些固定宽度字段,如字节和长整数。所以,像这样:

// I would have delimited these for clarity but I didn't want
// to imply that the stream was delimited because it's not.
StringbyteStringStringbytebytebytelonglongbytelonglong

我知道(并且有一些说法)正在发生的数据包的格式,我需要做的是为每个字符串值读取“行”,但是为字节读取固定数量的字节和多头。到目前为止,我提出的解决方案是使用while循环将字节读入临时字节数组,直到有换行符。然后,将字节转换为字符串。这对我来说似乎很尴尬,但我没有看到另一种显而易见的方式。我意识到我可以使用StreamReader.ReadLine(),但这将涉及另一个流,我已经有NetworkStream。但如果这是更好的解决方案,我会试一试。

我考虑的另一个选择是让我的后端团队为那些String值的长度写一个或两个字节,这样我就可以读取长度,然后根据指定的长度读取字符串。

所以,正如你所看到的,我有一些选择如何解决这个问题,我希望你能得到关于你认为最好的方法的意见。这是我现在用于以字符串形式读取整个数据包的代码。下一步是打破数据包的各个字段,并根据数据包中的数据完成需要完成的实际编程工作,创建对象,更新UI等。

string line = null;  
while (stream.DataAvailable)
{  
    //Get the packet length;  
    UInt16 packetLength = 0;  
    header = new byte[2];  
    stream.Read(header, 0, 2);  
    // Need to reverse the header array for BitConverter class if architecture is little endian.  
    if (BitConverter.IsLittleEndian)
        Array.Reverse(header);  
    packetLength = BitConverter.ToUInt16(header,0);

    buffer = new byte[packetLength];
    stream.Read(buffer, 0, BitConverter.ToUInt16(header, 0));
    line = System.Text.ASCIIEncoding.ASCII.GetString(buffer);
    Console.WriteLine(line);
}

2 个答案:

答案 0 :(得分:9)

就我个人而言

  1. 将Int16放在开头 字符串,所以你知道多久 他们会成为,
  2. 使用IO.BinaryReader类 读书,它会“读”,整理, 字符串,字符等变为变量,例如BinReader.ReadInt16()将读取两个字节,返回它们代表的int16,并在流中移动两个字节
  3. 希望这有帮助。

    P.S。使用ReadString方法时要小心,它假定字符串前面有自定义的7位整数,即它是由BinaryWriter类编写的。 以下内容来自CodeGuru帖子

      

    BinaryWriter类有两种方法   用于写字符串:重载   Write()方法和WriteString()   方法。前者写入字符串   作为一个字节流根据   编码该类正在使用。该   WriteString()方法也使用了   指定编码,但它是前缀   字符串的字节流与   字符串的实际长度。这样   带有前缀的字符串在via中读回   BinaryReader.ReadString()。

         

    关于长度的有趣之处   将其视为尽可能少的字节   用来保持这个尺寸,它是   存储为一种称为7位的类型   编码整数。如果长度适合   如果是,则使用7位单个字节   高于此高位   第一个字节设置,第二个字节   通过移动值创建字节   按7位。这是重复的   连续的字节,直到有   足够的字节来保存值。这个   机制用于确保   长度不会成为一个   采取的大部分尺寸   由序列化字符串组成。   BinaryWriter和BinaryReader都有   读写7位的方法   编码整数,但它们是   受保护,因此您只能使用它们   如果你从这些类中派生出来。

答案 1 :(得分:5)

我会使用长度为前缀的字符串。它会让你的生活变得更简单,这意味着你可以用换行符表示字符串。虽然对你的代码有一些评论:

  • 不要使用Stream.DataAvailable。仅仅因为没有可用的数据现在并不意味着你已经阅读了流的结尾。
  • 除非您完全确定自己永远不需要ASCII以外的文字,否则请勿使用ASCIIEncoding。
  • 不要认为Stream.Read会读取您要求的所有数据。 始终检查返回值。
  • BinaryReader使这很容易很多(包括长度前缀的字符串和读取循环,直到它读到你要求的内容)
  • 你在相同的数据上调用BitConverter.ToUInt16两次。为什么?