从BitArray转换为Byte

44

我有一个长度为8的 BitArray,我需要一个将它转换成 byte 的函数。如何实现?

具体来说,我需要一个正确的 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);
9个回答

67

这应该可以正常工作:

byte ConvertToByte(BitArray bits)
{
    if (bits.Count != 8)
    {
        throw new ArgumentException("bits");
    }
    byte[] bytes = new byte[1];
    bits.CopyTo(bytes, 0);
    return bytes[0];
}

17
注意:这将以相反的顺序计算位,例如示例中的BitArray会转换为128而不是1! - tehvan
为什么会以相反的顺序发生? - Kornelije Petak
1
@kornelijepetak:这就是BitArray的工作方式,就是在选择复制值方面的方法。 - Jon Skeet
4
重要的是按相反的顺序进行复制。如果您在其他类型上使用BitConverter,则它们以小端格式存储。 - user295190
4
重要的是区分字节序和位序。位序告诉你每个字节中比特的顺序,以及第一个比特是最重要的还是最不重要的。字节序告诉你单词中字节的期望顺序。位序通常被描述为“LSB first”或“MSB first”,而不是小端或大端。 - Tim
2
要反转顺序:var reversed = new BitArray(bitArray.Cast<bool>().Reverse().ToArray()); - Maxence

39

有些晚发布了,但这对我有用:

public static byte[] BitArrayToByteArray(BitArray bits)
{
    byte[] ret = new byte[(bits.Length - 1) / 8 + 1];
    bits.CopyTo(ret, 0);
    return ret;
}

适用于:

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

.


15
不要使用"bits.Length / 8",应该使用"(bits.Length - 1) / 8 + 1",否则如果BitArray的长度为7,则你的字节数组将为空。"-1"部分确保8的倍数不会加一。感谢https://dev59.com/73VD5IYBdhLWcg3wU56H#503201。 - iano
1
好的观点。我猜 Math.Max(1, bits.Length / 8) 也可以(稍微更易读一些)。我总是操作8位字节,所以我没有考虑下溢条件。 - Tedd Hansen
2
@TeddHansen 15怎么样? - Ark-kun
应为"byte[(bits.Length - 1) / 8 - 1]",否则会在字节数组末尾添加不必要的“0”字节。 - Güven Acar
这里的要求是 bits.Length / 8 应该向上取整,因此应该是 (int)Math.Ceiling[bits.Length / 8]。我们可以简化这个式子,因为我们知道 bits.Length 是一个正整数:(bits.Length + 8 - 1) / 8 == (bits.Length + 7) / 8。对于 bits.Length == 0,这个公式方便地返回 0 - adyavanapalli
显示剩余2条评论

9
一个穷人的解决方案:
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;
}

6

不幸的是,BitArray类在.Net Core类(UWP)中只有部分实现。例如,BitArray类无法调用CopyTo()和Count()方法。我编写了此扩展以填补这一空白:

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

该方法使用LSB(最低有效字节)逻辑将BitArray解码为字节数组。这是BitArray类使用的相同逻辑。将MSB参数设置为true调用该方法将产生一个MSB解码的字节序列。在这种情况下,请记住您可能还需要反转最终输出的字节集合。


5
这应该能解决问题。然而,之前的答案很可能是更好的选择。
    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;
    }

在你发布的示例中,结果字节将为0x80。换句话说,BitArray中的第一个值对应于返回字节中的第一个位。


1
@Tvde1 result 从未进行左移操作。设置的位将分别左移正确的数量 i,然后与 result 进行按位或运算。更详细的写法是:result = result | ((byte)(1 << i)) - Caleb Vear
不用理会我的评论 :) - Tvde1

2

这应该是最终的选择。适用于任何长度的数组。

private List<byte> BoolList2ByteList(List<bool> values)
    {

        List<byte> ret = new List<byte>();
        int count = 0;
        byte currentByte = 0;

        foreach (bool b in values) 
        {

            if (b) currentByte |= (byte)(1 << count);
            count++;
            if (count == 7) { ret.Add(currentByte); currentByte = 0; count = 0; };              

        }

        if (count < 7) ret.Add(currentByte);

        return ret;

    }

我认为这里有一个错误 - 因为 count++; 已经执行了,下一行应该是 if (count == 8) {...} - Stephen Rudolph

1
除了@JonSkeet的答案外,您还可以使用以下扩展方法:
public static byte ToByte(this BitArray bits)
{
    if (bits.Count != 8)
    {
        throw new ArgumentException("bits");
    }
    byte[] bytes = new byte[1];
    bits.CopyTo(bytes, 0);
    return bytes[0];
}

并且使用方式如下:

BitArray foo = new BitArray(new bool[]
{
    false, false, false, false,false, false, false, true
});

foo.ToByte();

0
byte GetByte(BitArray input)
{
  int len = input.Length;
  if (len > 8)
    len = 8;
  int output = 0;
  for (int i = 0; i < len; i++)
    if (input.Get(i))
      output += (1 << (len - 1 - i)); //this part depends on your system (Big/Little)
      //output += (1 << i); //depends on system
  return (byte)output;
}

干杯!


0

小端字节数组转换器:位数组中的第一位(索引为“0”)被假定为表示最不重要的位(位八位中的最右边的位),并将其解释为二进制的“零”或“一”。

 public static class BitArrayExtender {

    public static byte[] ToByteArray( this BitArray bits ) {

        const int BYTE = 8;
        int length = ( bits.Count / BYTE ) + ( (bits.Count % BYTE == 0) ? 0 : 1 );
        var bytes  = new byte[ length ];

        for ( int i = 0; i < bits.Length; i++ ) {

           int bitIndex  = i % BYTE;
           int byteIndex = i / BYTE;

           int mask = (bits[ i ] ? 1 : 0) << bitIndex;
           bytes[ byteIndex ] |= (byte)mask;

        }//for

        return bytes;

    }//ToByteArray

 }//class

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接