35

How do you convert a string such as "01110100011001010111001101110100" to a byte array then used File.WriteAllBytes such that the exact binary string is the binary of the file. In this case it would be the the text "test".

ParoX
  • 5,685
  • 23
  • 81
  • 152

5 Answers5

48

In case you don't have this LINQ fetish, so common lately, you can try the normal way

string input ....
int numOfBytes = input.Length / 8;
byte[] bytes = new byte[numOfBytes];
for(int i = 0; i < numOfBytes; ++i)
{
    bytes[i] = Convert.ToByte(input.Substring(8 * i, 8), 2);
}
File.WriteAllBytes(fileName, bytes);

LINQ is great but there must be some limits.

Maciej Hehl
  • 7,895
  • 1
  • 22
  • 23
  • 5
    This assumes that the string length is a multiple of 8... But you're right, it is probably easier to understand that way. I guess I'm totally addicted to LINQ ;) – Thomas Levesque Aug 08 '10 at 23:30
  • 2
    Hmm. I'd argue that the LINQ is more understandable. It describes concisely what is being done without describing the (noisy) steps to acheive that goal. It has a much higher content to noise ratio. – spender Aug 09 '10 at 00:04
  • 3
    @spender Sure LINQ is a nice tool for uses it was meant for, but for this simple and straightforward case? Come on, Thomas's code is longer, creates at least 4 enumerable objects, one intermediate array of strings, 5 delegates, and an anonymous reference type for every digit '0' or '1'. This is insane. – Maciej Hehl Aug 09 '10 at 17:48
  • 4
    if `input.Length / 8` is not properly rounded, if the double value is 1.75, numOfBytes is 1. Beware of that! – Phate01 Oct 22 '15 at 13:00
12

You could start by splitting the string into a sequence of 8-character strings, then convert those strings to bytes, and eventually write the bytes to a file

string input = "01110100011001010111001101110100";
var bytesAsStrings =
    input.Select((c, i) => new { Char = c, Index = i })
         .GroupBy(x => x.Index / 8)
         .Select(g => new string(g.Select(x => x.Char).ToArray()));
byte[] bytes = bytesAsStrings.Select(s => Convert.ToByte(s, 2)).ToArray();
File.WriteAllBytes(fileName, bytes);

EDIT: here's another way to split the string into 8-character chunks, perhaps a bit simpler :

int nBytes = (int)Math.Ceiling(input.Length / 8m);
var bytesAsStrings =
    Enumerable.Range(0, nBytes)
              .Select(i => input.Substring(8 * i, Math.Min(8, input.Length - 8 * i)));

If you know that the length of the string is a multiple of 8, you can make it even simpler :

int nBytes = input.Length / 8;
var bytesAsStrings =
    Enumerable.Range(0, nBytes)
              .Select(i => input.Substring(8 * i, 8));
Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758
  • Just bumped into this question. A nice toy problem... good for an interview. I thought I'd give it a shot before reading the answers. Matched your second approach virtually term for term. I too am addicted to LINQ! +1 – spender Aug 09 '10 at 00:06
4

Actually the answer by @Maciej is not correct. As @Phate01 noticed the numOfBytes is correct only for input length which is a power of 8. The second thing is that the byte array should be populated from n to 0 index not the opposite way. Here's the code example:

var bits = "000011110000001000";
var numOfBytes = (int)Math.Ceiling(bits.Length / 8m);
var bytes = new byte[numOfBytes];
var chunkSize = 8;

for (int i = 1; i <= numOfBytes; i++)
{
    var startIndex = bits.Length - 8 * i;
    if (startIndex < 0)
    {
        chunkSize = 8 + startIndex;
        startIndex = 0;
    }
    bytes[numOfBytes - i] = Convert.ToByte(bits.Substring(startIndex, chunkSize), 2);
}

This can be improved to get rid of the if statetment but in this form it's more understandable.

helencrump
  • 1,351
  • 1
  • 18
  • 27
kriskot
  • 303
  • 1
  • 8
4

A bit late, but here's my 2 cents:

var binaryStr = "01110100011001010111001101110100";

var byteArray = Enumerable.Range(0, int.MaxValue/8)
                          .Select(i => i*8)
                          .TakeWhile(i => i < binaryStr.Length)
                          .Select(i => binaryStr.Substring(i, 8))
                          .Select(s => Convert.ToByte(s, 2))
                          .ToArray();
File.WriteAllBytes("C:\temp\test.txt", byteArray);
theburningmonk
  • 15,701
  • 14
  • 61
  • 104
1

The other answers have you covered, but just for fun I wrote the opposite. Going from the string to the ascii binary representation:

    private static string StringToAsciiBin(string s)
    {
        string output = "";
        foreach (char c in s.ToCharArray())
        {
            for (int i = 128; i >= 1; i /=2)
            {
                if (((int)c & i) > 0)
                {
                    output += "1";
                }
                else
                {
                    output += "0";
                }
            }
        }
        return output;
    }
jwsample
  • 2,401
  • 19
  • 18
  • 2
    You would want to go from a byte array to the binary represenation. A char is a 16 bit data type, so you would chop off the top eight bits of each character code. Also, don't use += to build a string, it scales terribly badly, use a StringBuilder instead. – Guffa Aug 08 '10 at 23:36
  • @Guffa Agreed on using `StringBuilder`, but if you have `"01110100011001010111001101110100"` as an input, sorry, that's a string, not a `byte[]`, until you separate it out into blocks of 8. – vapcguy Apr 05 '18 at 20:49