Проблема BinaryWriter - «код добавляет некоторый байт между методом Write ()» - PullRequest
0 голосов
/ 02 сентября 2011

Я пытаюсь сделать некоторый код, используя BinaryWriter, а затем BinaryReader.Когда я хочу писать, я использую метод Write ().Но проблема в том, что между двумя строками метода Write появляется новый байт, который находится в ASCII-таблице в десятичном виде 31 (иногда 24).Вы можете видеть это на этом изображении:

enter image description here

Вы можете видеть, что байт в индексе 4 (5-й байт) имеет десятичное значение ASCII 31. Я не вставил его туда.Как вы можете видеть, первые 4 байта зарезервированы для числа (Int32), затем идут другие данные (в основном некоторый текст - сейчас это не важно).

Как видно из кода, который я пишу: - в1-я строка номер 10 - во 2-й строке текст «Это какой-то текст ...»

Как получился этот 5-й байт (31 декабря) между ??

И вот код, который у меня есть:

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;
                    }
                }
            }
        }
    }

Ответы [ 6 ]

4 голосов
/ 02 сентября 2011

Если вы посмотрите документацию для Write(string), вы увидите, что она записывает строку с префиксом длины . Таким образом, 31 - это количество символов в вашей строке - совершенно нормально.

3 голосов
/ 02 сентября 2011

Возможно, вам следует использовать Encoding.GetBytes , а затем записать байты вместо записи строки

, например

     bw.Write(
          Encoding.UTF8.GetBytes("This is some text at command " + commandNumbers[i])
     );
2 голосов
/ 02 сентября 2011

Когда строка записывается в двоичный поток, первое, что она делает, это записывает длину строки. Строка «Это некоторый текст в команде 10» содержит 31 символ, что является значением, которое вы видите.

1 голос
/ 02 сентября 2011

Вы должны проверить документацию методов, которые вы используете, прежде чем задавать вопросы о них:

Строка с префиксом длины представляет длину строки, добавляя к строке один байтили слово, которое содержит длину этой строки.Этот метод сначала записывает длину строки в виде целого числа без знака в кодировке UTF-7, а затем записывает такое количество символов в поток, используя текущую кодировку экземпляра BinaryWriter.

; -)

(Хотя на самом деле это LEB128 , а не UTF-7, согласно Википедии).

0 голосов
/ 02 сентября 2011

Хорошо, вот мой отредактированный код.Я удалил BinaryWriter (пока BinaryReader все еще там !!), и теперь он работает очень хорошо - больше никаких лишних байтов.

Что вы делаете?Есть ли что-нибудь, чтобы сделать лучше, чтобы он работал быстрее?Особенно мне интересен тот цикл foreach, который читает из другого метода, типа возвращаемого результата !!

Новый код:

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;
                    }
                }
            }
        }
    }
0 голосов
/ 02 сентября 2011

Причина этого байта в том, что вы добавляете переменное количество информации, поэтому необходима длина.Если бы вы добавили две строки, где бы вы узнали, где закончился первый и начался второй?

Если вы действительно не хотите или не нуждаетесь в этом байте длины, вы всегда можете преобразовать строку в байтовый массив и использовать его.

...