Convert from BitArray to Byte
Solution 1
This should work:
byte ConvertToByte(BitArray bits)
{
if (bits.Count != 8)
{
throw new ArgumentException("bits");
}
byte[] bytes = new byte[1];
bits.CopyTo(bytes, 0);
return bytes[0];
}
Solution 2
A bit late post, but this works for me:
public static byte[] BitArrayToByteArray(BitArray bits)
{
byte[] ret = new byte[(bits.Length - 1) / 8 + 1];
bits.CopyTo(ret, 0);
return ret;
}
Works with:
string text = "Test";
byte[] bytes = System.Text.Encoding.ASCII.GetBytes(text);
BitArray bits = new BitArray(bytes);
bytes[] bytesBack = BitArrayToByteArray(bits);
string textBack = System.Text.Encoding.ASCII.GetString(bytesBack);
// bytes == bytesBack
// text = textBack
.
Solution 3
A poor man's solution:
protected byte ConvertToByte(BitArray bits)
{
if (bits.Count != 8)
{
throw new ArgumentException("illegal number of bits");
}
byte b = 0;
if (bits.Get(7)) b++;
if (bits.Get(6)) b += 2;
if (bits.Get(5)) b += 4;
if (bits.Get(4)) b += 8;
if (bits.Get(3)) b += 16;
if (bits.Get(2)) b += 32;
if (bits.Get(1)) b += 64;
if (bits.Get(0)) b += 128;
return b;
}
Solution 4
This should do the trick. However the previous answer is quite likely the better option.
public byte ConvertToByte(BitArray bits)
{
if (bits.Count > 8)
throw new ArgumentException("ConvertToByte can only work with a BitArray containing a maximum of 8 values");
byte result = 0;
for (byte i = 0; i < bits.Count; i++)
{
if (bits[i])
result |= (byte)(1 << i);
}
return result;
}
In the example you posted the resulting byte will be 0x80. In other words the first value in the BitArray coresponds to the first bit in the returned byte.
Solution 5
Unfortunately, the BitArray class is partially implemented in .Net Core class (UWP). For example BitArray class is unable to call the CopyTo() and Count() methods. I wrote this extension to fill the gap:
public static IEnumerable<byte> ToBytes(this BitArray bits, bool MSB = false)
{
int bitCount = 7;
int outByte = 0;
foreach (bool bitValue in bits)
{
if (bitValue)
outByte |= MSB ? 1 << bitCount : 1 << (7 - bitCount);
if (bitCount == 0)
{
yield return (byte) outByte;
bitCount = 8;
outByte = 0;
}
bitCount--;
}
// Last partially decoded byte
if (bitCount < 7)
yield return (byte) outByte;
}
The method decodes the BitArray to a byte array using LSB (Less Significant Byte) logic. This is the same logic used by the BitArray class. Calling the method with the MSB parameter set on true will produce a MSB decoded byte sequence. In this case, remember that you maybe also need to reverse the final output byte collection.
Comments
-
Graviton almost 2 years
I have a
BitArray
with the length of 8, and I need a function to convert it to abyte
. How to do it?Specifically, I need a correct function of
ConvertToByte
:BitArray bit = new BitArray(new bool[] { false, false, false, false, false, false, false, true }); //How to write ConvertToByte byte myByte = ConvertToByte(bit); var recoveredBit = new BitArray(new[] { myByte }); Assert.AreEqual(bit, recoveredBit);
-
tehvan about 15 yearsMind: this computes the bits in reverse order, e.g. the BitArray from the example will convert into 128, not 1!
-
Kornelije Petak over 14 yearsWhy does this happen in a reverse order?
-
Jon Skeet over 14 years@kornelijepetak: That's just the way that BitArray works, in terms of the way it chooses to copy values.
-
Admin over 13 years@kornelijepetak: It is important that it copies in reverse order. If you use BitConverter on other types they are stored in little-endian format.
-
user1393201 over 12 yearsInstead of "bits.Length / 8", you should use "(bits.Length - 1) / 8 + 1", otherwise if the BitArray has a length of 7, your byte array will be empty. The "- 1" part makes sure a multiple of 8 will not return plus one. Thanks to stackoverflow.com/questions/17944/…
-
Tedd Hansen over 12 yearsGood point. A Math.Max(1, bits.Length / 8) will also work I guess (slightly more readable). I always operate on 8 bit bytes so I haven't considered the underflow condition.
-
Stephen Rudolph over 9 yearsI believe there's a bug here - since
count++;
has already fired, the next line should beif (count == 8) {...}
-
Tim over 9 yearsIts important to draw the distinction between byte endianness and bit endianness. Bit endianness tells you the ordering of the bits in each byte and whether the first bit is the most or least significant bit. Byte endianness tells you the expected order of the bytes in a word. Bit endianess is usually always described as "LSB first" or "MSB first" rather than little-endian or big-endian...
-
Maxence over 8 yearsTo reverse the order:
var reversed = new BitArray(bitArray.Cast<bool>().Reverse().ToArray());
-
Ark-kun over 7 years@TeddHansen What about 15?
-
Extragorey almost 6 yearsThis doesn't handle the empty case, mind - might want to add a check for when
bits
is empty and return an emptybyte[]
array accordingly. -
Güven Acar over 5 yearsShould be "byte[(bits.Length - 1) / 8 - 1", otherwise adding unnecessary "0" byte end of byte array.
-
adyavanapalli over 5 yearsThe requirement here is that
bits.Length / 8
should round up, hence it should be(int)Math.Ceiling[bits.Length / 8]
. We can simply this because we know thatbits.Length
is a positive integer:(bits.Length + 8 - 1) / 8
==(bits.Length + 7) / 8
. Forbits.Length == 0
, the formula conveniently returns0
. -
Ben Jaguar Marshall over 5 yearsI use (bits.Length + 7) >> 3. This will always round up.
-
Caleb Vear about 2 years@Tvde1
result
is never left shifted. Bits that are set are individually left shifted the correct amounti
and then a bitwise or is done with result. A more verbose way of writing that line is:result = result | ((byte)(1 << i))
. -
Tvde1 about 2 yearsNever mind my comment :)