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

jxp*_*777 7 .net c# 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
Run Code Online (Sandbox Code Playgroud)

我知道(并且有一些说法)正在发生的数据包的格式,我需要做的是读取每个字符串值的"行",但读取字节和长度的固定字节数.到目前为止,我提出的解决方案是使用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);
}
Run Code Online (Sandbox Code Playgroud)

Bin*_*ier 9

就我个人而言

  1. 把一个Int16放在字符串的开头,这样你就可以知道它们将会持续多长时间,并且
  2. 使用IO.BinaryReader类进行读取,它将"读取",整数,字符串,字符等变为变量,例如BinReader.ReadInt16()将读取两个字节,返回它们表示的int16,并在其中移动两个字节流

希望这可以帮助.

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

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

关于长度值的有趣之处在于,尽可能少的字节用于保存此大小,它被存储为称为7位编码整数的类型.如果长度适合7位,则使用单个字节,如果大于此,则设置第一个字节的高位,并通过将值移位7位来创建第二个字节.这将以连续的字节重复,直到有足够的字节来保存该值.此机制用于确保长度不会成为序列化字符串占用的大小的重要部分.BinaryWriter和BinaryReader具有读取和写入7位编码整数的方法,但它们受到保护,因此只有从这些类派生时才能使用它们.


Jon*_*eet 5

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

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