2009-01-29 177 views
6

我有一个字节数组,我从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。但如果这是更好的解决方案,我会给它一个机会。

我考虑的另一个选择是让我的后端团队为这些字符串值的长度写入一个或两个字节,以便我可以读取长度,然后根据指定的长度读取字符串。因此,正如你所看到的,我有一些关于如何解决这个问题的选择,并且我希望你对你认为最好的方式提出意见。以下是我现在用于读取整个数据包的字符串的代码。下一步是打破数据包的各个领域,根据数据包中的数据完成需要完成的实际编程工作,创建对象,更新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); 
} 

回答

9

我个人

  1. 把一个Int16类型的 字符串的开始,所以你知道他们要去 要等多久,并
  2. 使用IO.BinaryReader类到 做的读,它会“读”,整数, 字符串,字符等等变量变量BinReader.ReadInt16()将读取两个字节,返回它们表示的int16,并在流中移动两个字节

希望这有助于。

P.S.使用ReadString方法时要小心,它假设该字符串前面是自定义的7位整数,即它是由BinaryWriter类写入的。 以下是这CodeGuru

的的BinaryWriter类有字符串写入两种方法 :重载 Write()方法和WriteString()方法 。前者根据 编码类所使用的字节流将字符串 写入。 WriteString()方法也使用 指定的编码,但它将 字符串的字节流与 字符串的实际长度作为前缀。这样的 前缀字符串通过 BinaryReader.ReadString()读回。

绕长度 值有趣的认为尽可能 为几个字节用于保存这个大小,它是 存储为所谓的7位 编码整数类型。如果长度适合于7位,则使用单个字节,如果它大于 ,则第一个字节被设置为 的高位,并且通过将值 移位7位来创建第二个 字节。这是连续字节 重复,直到有 足够的字节来保存该值。这个机制用于确保 的长度不会成为 大小的一部分,其大小取决于序列化的字符串所带的大小 。 BinaryWriter和BinaryReader有 方法读取和写入7位 编码整数,但它们是 受保护,因此如果您从这些类派生,则只能使用它们 。

+0

以前没有遇到过BinaryReader。这看起来对于我正在处理的所有这些东西都是非常有帮助的。谢谢! – jxpx777 2009-01-29 17:09:07

5

我会去与长度前缀的字符串。它将使你的生活简单得多,它意味着你可以代表与换行符字符串在代码的一些意见,虽然:

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