Reading a string from a byte array (not converting a byte array to a string)

I have a byte array that I am reading in NetworkStream. The first two bytes indicate the length of the subsequent packet, and then the packet is read into an array of bytes of this length. The data I need to read from the NetworkStream / byte array has several lines, that is, variable-length data ending with new lowercase characters, and some fixed-width fields, such as bytes and long. So something like this:

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

I know (and mean) the data packet format that occurs, and what I need to do is read the "string" for each string value, but read a fixed number of bytes for bytes and long. So far, my proposed solution has been to use a while to read bytes into the temp byte array until a newline appears. Then convert the bytes to a string. This seems awkward to me, but I see no other obvious way. I understand that I can use StreamReader.ReadLine() , but this will be connected to another stream, and I already have NetworkStream . But if this is the best solution, I will do it.

Another option that I considered is for my backend command to write bytes or two for these line lengths so that I can read the length and then read the line based on the specified length.

So, as you can see, I have some options for how to do this, and I would like you to talk about what you think is the best way to do this. Here is the code that I have right now for reading in the entire package as a string. The next step is to break down the various fields of the package and do the actual programming work that needs to be done, creating objects, updating the user interface, etc. Based on the data in the package.

 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); } 
+6
c # bytearray networkstream
source share
2 answers

Personally, I would

  • Put Int16 at the beginning of the line so you know how long they will be, and
  • Use the IO.BinaryReader class to do the reading, it will "read", ints, strings, characters, etc. into variables, for example. BinReader.ReadInt16 () will read two bytes, return the int16 they represent, and move the two bytes to the stream

Hope this helps.

PS Be careful using the ReadString method, it assumes that the string is appended to custom 7-bit integers, i.e. That it was recorded by the BinaryWriter class. Below is the CodeGuru post

The BinaryWriter class has two methods for writing strings: the Write () overload and the WriteString () method. The first writes the string as a stream of bytes in accordance with the encoding class used. The WriteString () method also uses the specified encoding, but prefixes the string byte stream with the actual string length. such prefix strings are read through BinaryReader.ReadString ().

The interesting thing about length is to estimate that as few bytes as possible are used to store this size, it is stored as a type called a 7-bit encoded integer. If the length corresponds to 7 bits, one byte is used, if it is greater than this, then the high bit on the first byte is set and the second byte is created by shifting the value by 7 bits. This is repeated with consecutive bytes until there are enough bytes to hold the value. This mechanism is used for the length does not become a significant part of the size made using a serialized string. BinaryWriter and BinaryReader have methods for reading and writing 7-bit encoded integers, but they are protected, and therefore you can only use them if you exit these classes.

+9
source share

I would take lines with a length prefix. This will make your life a lot easier, and that means you can represent lines with line breaks. A few comments on your code:

  • Do not use Stream.DataAvailable. Just because there is no data available does not mean you read the end of the stream.
  • If you are absolutely sure that you will not need text outside of ASCII, do not use ASCIIEncoding.
  • Do not assume that Stream.Read will read all the data you request. Always check the return value.
  • BinaryReader makes a lot of this much easier (including lines with a prefix of length and Read that are sung until they read what you requested)
  • You call BitConverter.ToUInt16 twice on the same data. Why?
+5
source share

All Articles