Question

I am try to do some code using BinaryWriter and Then BinaryReader. When I wanna write I use method Write(). But the problem is that between two lines of Write method there appears a new byte which is in ASCII table in decimal 31 (sometines 24). You can see it on this image:

enter image description here

You can see that byte at index 4 (5th byte) is of ASCII decimal value 31. I didnt insert it there. As you can see 1st 4 bytes are reserved for a number (Int32), next are other data (some text mostly - this is not important now).

As you can see from the code i write: - into 1st line a number 10 - into 2nd line text "This is some text..."

How come came that 5th byte (dec 31) in between??

And this is the code I have:

static void Main(string[] args)
    {           
        //
        //// SEND - RECEIVE:
        //
        SendingData();
        Console.ReadLine();
    }

    private static void SendingData()
    {
        int[] commandNumbers = { 1, 5, 10 }; //10 is for the users (when they send some text)!

        for (int i = 0; i < commandNumbers.Length; i++)
        {
            //convert to byte[]
            byte[] allBytes;
            using (MemoryStream ms = new MemoryStream())
            {
                using (BinaryWriter bw = new BinaryWriter(ms))
                {
                    bw.Write(commandNumbers[i]);   //allocates 1st 4 bytes - FOR MAIN COMMANDS!
                    if (commandNumbers[i] == 10)
                        bw.Write("This is some text at command " + commandNumbers[i]); //HERE ON THIS LINE IS MY QUESTION!!!
                }
                allBytes = ms.ToArray();
            }

            //convert back:
            int valueA = 0;
            StringBuilder sb = new StringBuilder();
            foreach (var b in GetData(allBytes).Select((a, b) => new { Value = a, Index = b }))
            {
                if (b.Index == 0) //1st num
                    valueA = BitConverter.ToInt32(b.Value, 0);
                else //other text
                {
                    foreach (byte _byte in b.Value)
                        sb.Append(Convert.ToChar(_byte));
                }
            }

            if (sb.ToString().Length == 0)
                sb.Append("ONLY COMMAND");
            Console.WriteLine("Command = {0} and Text is \"{1}\".", valueA, sb.ToString());
        }
    }

    private static IEnumerable<byte[]> GetData(byte[] data)
    {
        using (MemoryStream ms = new MemoryStream(data))
        {
            using (BinaryReader br = new BinaryReader(ms))
            {
                int j = 0;
                byte[] buffer = new byte[4];
                for (int i = 0; i < data.Length; i++)
                {
                    buffer[j++] = data[i];
                    if (i == 3) //SENDING COMMAND DATA
                    {
                        yield return buffer;
                        buffer = new byte[1];
                        j = 0;
                    }
                    else if (i > 3) //SENDING TEXT
                    {
                        yield return buffer;
                        j = 0;
                    }
                }
            }
        }
    }
Was it helpful?

Solution

If you look at the documentation for Write(string), you'll see that it writes a length-prefixed string. So the 31 is the number of characters in your string -- perfectly normal.

OTHER TIPS

You should probably be using Encoding.GetBytes and then write the bytes instead of writing a string

for example

     bw.Write(
          Encoding.UTF8.GetBytes("This is some text at command " + commandNumbers[i])
     );

When a string is written to a binary stream, the first thing it does is write the length of the string. The string "This is some text at command 10" has 31 characters, which is the value you're seeing.

You should check the documentation of methods you use before asking questions about them:

A length-prefixed string represents the string length by prefixing to the string a single byte or word that contains the length of that string. This method first writes the length of the string as a UTF-7 encoded unsigned integer, and then writes that many characters to the stream by using the BinaryWriter instance's current encoding.

;-)

(Though in fact it is an LEB128 and not UTF-7, according to Wikipedia).

The reason this byte is there because you're adding a variable amount of information, so the length is needed. If you were to add two strings, where would you know where the first ended and the second began?

If you really don't want or need that length byte, you can always convert the string to a byte array and use that.

Ok, here is my edited code. I removed BinaryWriter (while BinaryReader is still there!!), and now it works very well - no more extra bytes.

What do you thing? Is there anytihng to do better, to make it run faster? Expecially Im interesting for that foreach loop, which read from another method that is yield return type!!

New Code:

static void Main(string[] args)
    {           
        //
        //// SEND - RECEIVE:
        //
        SendingData();
        Console.ReadLine();
    }

    private static void SendingData()
    {
        int[] commands = { 1, 2, 3 }; 
        // 1 - user text
        // 2 - new game
        // 3 - join game
        // ...

        for (int i = 0; i < commands.Length; i++)
        {
            //convert to byte[]
            byte[] allBytes;
            using (MemoryStream ms = new MemoryStream())
            {
                // 1.st - write a command:
                ms.Write(BitConverter.GetBytes(commands[i]), 0, 4);
                // 2nd - write a text:                                         
                if (commands[i] == 1)
                {
                    //some example text (like that user sends it):
                    string myText = "This is some text at command " + commands[i];
                    byte[] myBytes = Encoding.UTF8.GetBytes(myText);
                    ms.Write(myBytes, 0, myBytes.Length);
                }
                allBytes = ms.ToArray();
            }

            //convert back:
            int valueA = 0;
            StringBuilder sb = new StringBuilder();
            foreach (var b in ReadingData(allBytes).Select((a, b) => new { Value = a, Index = b }))
            {
                if (b.Index == 0)
                {
                    valueA = BitConverter.ToInt32(b.Value, 0);
                }
                else
                {
                    sb.Append(Convert.ToChar(b.Value[0]));
                }
            }

            if (sb.ToString().Length == 0)
                sb.Append("ONLY COMMAND");
            Console.WriteLine("Command = {0} and Text is \"{1}\".", valueA, sb.ToString());
        }            
    }

    private static IEnumerable<byte[]> ReadingData(byte[] data)
    {
        using (MemoryStream ms = new MemoryStream(data))
        {
            using (BinaryReader br = new BinaryReader(ms))
            {
                int j = 0;
                byte[] buffer = new byte[4];
                for (int i = 0; i < data.Length; i++)
                {
                    buffer[j++] = data[i];
                    if (i == 3) //SENDING COMMAND DATA
                    {
                        yield return buffer;
                        buffer = new byte[1];
                        j = 0;
                    }
                    else if (i > 3) //SENDING TEXT
                    {
                        yield return buffer;
                        j = 0;
                    }
                }
            }
        }
    }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top