1

I have a random integer value which I need to represent in String as a Byte array. For example:

int value = 32;
String strValue = getStringByteArray(value);
Console.WriteLine(strValue); // should write: " \0\0\0"

If value = 11 then getStringByteArray(value) shuld return "\v\0\0\0".

If value = 13 then getStringByteArray(value) shuld return "\r\0\0\0".

And so on.

Any idea on how to implement the method getStringByteArray(int value) in C#?

UPDATE

This is the code that receives the data from the C# NamedPipe Server:

bool CFilePipe::ReadString(int m_handle, string &value)
{
   //--- check for data
   if(WaitForRead(sizeof(int)))
     {
      ResetLastError();
      int size=FileReadInteger(m_handle);
      if(GetLastError()==0)
        {
         //--- check for data
         if(WaitForRead(size))
           {
            value=FileReadString(m_handle,size);
            return(size==StringLen(value));
           }
        }
     }
   //--- failure
   return(false);
}
5
  • What do you mean by "represent in String as a Byte array"? A string is a string, a byte array is a byte array. Do you really want unprintable characters in there? This sounds like a bad idea to me - what's the context? Commented Aug 19, 2015 at 18:07
  • @JonSkeet This is a prefix that represents the length of a message. And the String has to go in that exact format so the receiver can parse the String properly. Using NamedPipes protocol. So, the first 4 bytes of the message is the length of the message, and the rest of the bytes of the message is its content. Commented Aug 19, 2015 at 18:27
  • It sounds like you should be writing this as binary data rather than as a string. Fundamentally it isn't text, so don't try to act as if it is. Commented Aug 19, 2015 at 18:45
  • @JonSkeet What do you want me to say? It works embedded as text along with the message, and the message is received and parsed properly by the other endpoint. Commented Aug 19, 2015 at 18:50
  • And if you ever decide to propagate that text in a different way? Chances are very high it will break. I have seen hundreds and hundreds of people get bitten by treating arbitrary binary data as text over the years. Just don't. There's no need to here, so why do it? You've got a binary data stream over the named pipe - why introduce an extra level of text encoding to it pointlessly? See my answer for the approach I'd use. Commented Aug 19, 2015 at 18:51

5 Answers 5

8

Don't take this approach at all. You should be writing to a binary stream of some description - and write the binary data for the length of the packet/message, followed by the message itself. For example:

BinaryWriter writer = new BinaryWriter(stream);
byte[] data = Encoding.UTF8.GetBytes(text);
writer.Write(data.Length);
writer.Write(data);

Then at the other end, you'd use:

BinaryReader reader = new BinaryReader(stream);
int length = reader.ReadInt32();
byte[] data = reader.ReadBytes(length);
string text = Encoding.UTF8.GetString(data);

No need to treat binary data as text at all.

Sign up to request clarification or add additional context in comments.

5 Comments

Hi, thanks for your answer. Your method seems to work but partially. With the tests I ran using your method, I send the String "Avogadro" and the other terminal receives "Avogadr" with an unprintable char in the first character. Afterward, I increase the length by 1 and it receives the complete message but with an unprintable character in the beginning. What would be causing this?
@JoeAlmore: Hard to tell without seeing your actual test code.
Just added the code which receives the data from the NamedPipe Server. The code works, but it is retrieving one additional character in the beginning hence I have to increase the length of the message by 1. It reads first the four bytes of the message and then proceeds to read the message with that size. I test to send the very same String with the same method to a Java application, and Java receives the complete String without any additional character.
@JoeAlmore: Well we have no idea what FileReadInteger, FileReadString or StringLen do, which doesn't help. You need to work out what's happening to that additional byte - I suggest you try to look at exactly what binary data is being transmitted. This is definitely an implementation issue rather than a conceptual one - the idea of "write an integer, write the data" is a very simple and widely used one.
Those methods do what they say in their names. Anyways, I found the problem. That additional character is the size of the String embedded in the String itself. Seems like the NamedPipe server is still adding the length of the message in the first 4 bytes, regardless of having sent the length before. Well, that's no big deal, I can remove those four bytes from that client when it receives messages. Thanks.
2

Well. First of all you should get bytes from integer. You can do it with BitConverter:

var bytes = BitConverter.GetBytes(value);

Next, here is three variants. First - if you want to get result in binary format. Just take all your bytes and write as it is:

var str =  string.Concat(bytes.Select(b => Convert.ToString(b, 2)));

Second variant. If you want convert your byte array to hexadecimal string:

var hex = BitConverter.ToString(array).Replace("-","");     

Third variant. Your representation ("\v\0\0\0") - it is simple converting byte to char. Use this:

var s = bytes.Aggregate(string.Empty, (current, t) => current + Convert.ToChar(t));

3 Comments

Hi thanks for your answer but the output is not in binary nor in hex, this is the output \v\0\0\0.
I understood. Added third variant, it gives same result as you want. Check it please.
This is treating binary data as text, when it's not. It's very error prone, and should just be avoided to start with. Yes, it's what the OP sort of asked for (although admittedly not as simple a way as new string(bytes.Select(x => (char) x).ToArray())) but the underlying requirement is better solved by not using text for this at all.
1

This should help with that.

class Program
    {
        static void Main(string[] args)
        {
            Random rand = new Random();
            int number = rand.Next(1, 1000);
            byte[] intBytes = BitConverter.GetBytes(number);
            string answer = "";

            for (int i = 0; i < intBytes.Length; i++)
            {
                answer += intBytes[i] + @"\";
            }

            Console.WriteLine(answer);
            Console.WriteLine(number);

            Console.ReadKey();
        }
    }

Comments

1

Obviously, you should implement two steps to achieve the goal:

  1. Extract bytes from the integer in the appropriate order (little-endian or big-endian, it's up to you to decide), using bit arithmetics.

  2. Merge extracted bytes into string using the format you need.

Possible implementation:

using System;
using System.Text;

public class Test
{
    public static void Main()
    {
        Int32 value = 5152;
        byte[] bytes = new byte[4];
        for (int i = 0; i < 4; i++)
        {
            bytes[i] = (byte)((value >> i * 8) & 0xFF);
        }

        StringBuilder result = new StringBuilder();
        for (int i = 0; i < 4; i++)
        {
            result.Append("\\" + bytes[i].ToString("X2"));
        }

        Console.WriteLine(result);
    }
}

Ideone snippet: http://ideone.com/wLloo1

Comments

1

I think you are saying that you want to convert each byte into a character literal, using escape sequences for the non printable characters.

After converting the integer to 4 bytes, cast to char. Then use Char.IsControl() to identify the non-printing characters. Use the printable char directly, and use a lookup table to find the corresponding escape sequence for each non-printable char.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.