Преобразовать из BitArray в Byte

У меня есть BitArray длиной 8, и мне нужна функция, чтобы преобразовать его в 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);

person Graviton    schedule 18.02.2009    source источник


Ответы (9)


Это должно работать:

byte ConvertToByte(BitArray bits)
{
    if (bits.Count != 8)
    {
        throw new ArgumentException("bits");
    }
    byte[] bytes = new byte[1];
    bits.CopyTo(bytes, 0);
    return bytes[0];
}
person Jon Skeet    schedule 18.02.2009
comment
Mind: это вычисляет биты в обратном порядке, например BitArray из примера будет преобразован в 128, а не в 1! - person tehvan; 18.02.2009
comment
Почему это происходит в обратном порядке? - person Kornelije Petak; 04.02.2010
comment
@kornelijepetak: BitArray работает именно так, с точки зрения способа копирования значений. - person Jon Skeet; 04.02.2010
comment
@kornelijepetak: Важно копировать в обратном порядке. Если вы используете BitConverter для других типов, они сохраняются в формате с прямым порядком байтов. - person ; 04.10.2010
comment
Важно провести различие между порядком байтов и порядком байтов. Порядок байтов сообщает вам порядок битов в каждом байте и то, является ли первый бит самым или наименее значимым битом. Порядок байтов сообщает вам ожидаемый порядок байтов в слове. Битовый порядок байтов обычно всегда описывается как LSB first или MSB first, а не как little-endian или big-endian ... - person Tim; 11.11.2014
comment
Чтобы изменить порядок: var reversed = new BitArray(bitArray.Cast<bool>().Reverse().ToArray()); - person Maxence; 20.09.2015

Немного поздний пост, но это работает для меня:

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

.

person Tedd Hansen    schedule 06.01.2011
comment
Вместо bits.Length / 8 вы должны использовать (bits.Length - 1) / 8 + 1, иначе, если BitArray имеет длину 7, ваш массив байтов будет пуст. Часть - 1 гарантирует, что число, кратное 8, не вернет плюс один. Благодаря stackoverflow.com/questions/17944/ - person iano; 03.11.2011
comment
Хорошая точка зрения. Я думаю, Math.Max ​​(1, bits.Length / 8) также будет работать (немного более читаемый). Я всегда работаю с 8-битными байтами, поэтому я не учел состояние недостаточного заполнения. - person Tedd Hansen; 15.11.2011
comment
@TeddHansen А как насчет 15? - person Ark-kun; 01.12.2016
comment
Это не обрабатывает пустой регистр, помните - может потребоваться добавить проверку, когда bits пуст, и соответственно вернуть пустой массив byte[]. - person Extragorey; 06.07.2018
comment
Должен быть byte [(bits.Length - 1) / 8 - 1, в противном случае добавляется ненужный 0-байтовый конец байтового массива. - person Güven Acar; 25.09.2018
comment
Требование здесь состоит в том, чтобы bits.Length / 8 было округлено в большую сторону, следовательно, должно быть (int)Math.Ceiling[bits.Length / 8]. Мы можем просто это сделать, потому что знаем, что bits.Length является положительным целым числом: (bits.Length + 8 - 1) / 8 == (bits.Length + 7) / 8. Для bits.Length == 0 формула удобно возвращает 0. - person asfeynman; 27.11.2018
comment
Я использую (bits.Length + 7) ›› 3. Всегда округляется в большую сторону. - person Ben Jaguar Marshall; 31.01.2019

Решение для бедняков:

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;
}
person tehvan    schedule 18.02.2009

Это должно помочь. Однако предыдущий ответ, скорее всего, лучший вариант.

    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 соответствует первому биту возвращаемого байта.

person Caleb Vear    schedule 18.02.2009

К сожалению, класс 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;
}

Этот метод декодирует BitArray в массив байтов с использованием логики LSB (Less Significant Byte). Это та же логика, что используется классом BitArray. Вызов метода с параметром MSB, установленным на true, приведет к созданию байтовой последовательности, декодированной MSB. В этом случае помните, что вам также может потребоваться отменить окончательную коллекцию выходных байтов.

person LoxLox    schedule 01.12.2017

Это должно быть окончательное. Работает с массивами любой длины.

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;

    }
person Dmitry Kakhovsky    schedule 30.07.2011
comment
Я считаю, что здесь есть ошибка - поскольку count++; уже запущен, следующая строка должна быть if (count == 8) {...} - person Stephen Rudolph; 15.08.2014

В дополнение к ответу @ 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();
person Ali    schedule 05.07.2017

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

Ваше здоровье!

person NothinRandom    schedule 25.04.2013

Конвертер массива байтов с обратным порядком байтов: первый бит (с индексом «0») в BitArray, как предполагается, представляет наименее значимый бит (крайний правый бит в бит-октете), который интерпретируется как «ноль» или «единица» как двоичный.

 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
person underscore    schedule 25.10.2014