Получение битов из байтов

188
07 октября 2018, 05:10

Например есть 8 байт данных. Есть стартовый байт и стартовый бит - откуда нужно взять информацию, а также длина в битах(сколько нужно взять).

Как я могу достать из этих 8 байт например, с первого байта - 7 и 8 бит (т.е. стартовый байт №1, позиция стартового бита №7, длина 2 бита)

или например, с 3го бита второго байта взять 14 бит (то есть используется второй и третий байт)

Answer 1

Для того чтобы не "воевать" самому с битовыми операциями, можно воспользоваться стандартным классом BitSet:

public static BitSet getBitSet(byte[] array, int fromByteIndex, int fromByteBitIndex, int bitsCount)
{
    BitSet arrayBitSet = BitSet.valueOf(array);
    int fromIndex = fromByteIndex * 8 + fromByteBitIndex;
    return arrayBitSet.get(fromIndex, fromIndex + bitsCount);
}

И использование:

byte[] array = { 10, 1, 127 };
BitSet result = getBitSet(array, 1, 7, 2);
System.out.println(result.get(0));
System.out.println(result.get(1));

false
true

В BitSet индексы битов определяются так:

10 = 00001010
     76543210 - индексы

Если нужен обратный порядок:

10 = 00001010
     01234567 - индексы

то, как вариант, можно предварительно менять порядок битов в байтах:

public static BitSet getBitSet(byte[] array, int fromByteIndex, int fromByteBitIndex, int bitsCount)
{
    byte[] reversedBitsOrderArray = new byte[array.length];
    for (int i = 0; i < array.length; i++)
    {
        reversedBitsOrderArray[i] = reverseBitsOrder(array[i]);
    }
    BitSet arrayBitSet = BitSet.valueOf(reversedBitsOrderArray);
    int fromIndex = fromByteIndex * 8 + fromByteBitIndex;
    return arrayBitSet.get(fromIndex, fromIndex + bitsCount);
}
private static byte reverseBitsOrder(byte b)
{
    byte from = b;
    byte to = 0;
    for (int i = 0; i < 8; i++)
    {
        to <<= 1;
        to |= (from & 1);
        from >>= 1;
    }
    return to;
}

В принципе, в этом случае решение "взять биты вручную" становится короче и проще:

public static boolean[] getBits(byte[] array, int fromByteIndex, int fromByteBitIndex, int bitsCount)
{
    boolean[] bits = new boolean[bitsCount];
    int fromIndex = fromByteIndex * 8 + fromByteBitIndex;
    for (int i = 0; i < bitsCount; i++)
    {
        int byteIndex = (i + fromIndex) / 8;
        int bitIndex = (i + fromIndex) % 8;
        bits[i] = (array[byteIndex] & (1 << (7 - bitIndex))) != 0;
    }
    return bits;
}
Answer 2

Как это устроено "под капотом":

public static boolean getBitFromByte(byte b, int position) {
        // position = 6 - т.е. хотим получить 7 бит
        // 11010110 - b
        // & - побитовая операция И
        // 01000000 == (1 << 6) - сдвиг влево на 6 позиций (битов)
        // =
        // 01000000
        // затем сдвигаем обратно на 6 позиций вправо:
        // 01000000 >> 6 == 00000001 - что означает 7-й бит 
        //     данного байта b равен 1 (единице)
    return ((b & (1 << position)) >> position) == 1;
}
public static boolean getBitFromBytes(byte[] bs, int bytePos, int bitPos) {
    return getBitFromByte(bs[bytePos], bitPos);
}
public static byte setBitInByte(byte b, boolean bit, int position) {
    if (bit)
        return (byte)(b | (1 << position));
    else
        return (byte)(b & ~(1 << position));
}
// почему-то нельзя преобразовать в Java тип boolean к int, не используя условие
// поэтому приходится передавать установочный бит в типе int
public static byte setBitInByteFast(byte b, int bit, int position) {
    return (byte) (((1 - bit) * ~0) ^ ((((1 - bit) * ~0) ^ b) | (1 << position)));
}
public static void main( String[] args )
{
    byte b = 0;
    b = setBitInByte(b, true, 3);
    System.out.println(getBitFromByte(b, 3));
    b = setBitInByte(b, false, 3);
    System.out.println(getBitFromByte(b, 3));
    b = setBitInByteFast(b, 1, 3);
    System.out.println(getBitFromByte(b, 3));
    b = setBitInByteFast(b, 0, 3);
    System.out.println(getBitFromByte(b, 3));
}
Answer 3

Используйте побитовый AND:

byte[] bytes = {-1,2,3,4,5,6,7,8};
System.out.println((bytes[0] & 0x80) == 0x80); // 0x80 - 1000 0000 в двоичном коде 
System.out.println((bytes[0] & 0x40) == 0x40); // 0x40 - 0100 0000 в двоичном коде 

Результат:

true
true
READ ALSO
No registered metadata for type - Java EE

No registered metadata for type - Java EE

Не могу понять в чём проблемаOpenJpa выдаёт такую ошибку:

304
Bootstrap 4. Почему размер navbar настолько мал?

Bootstrap 4. Почему размер navbar настолько мал?

Адаптирую сайт под мобильные телефоны, столкнулся с такой проблемой что navbar который идет в примерах bootstrap невероятно малПриходиться на телефоне...

167
Ссылки footer не принимают элемент float right

Ссылки footer не принимают элемент float right

Я пытаюсь сделать так, чтобы текст был слева и имел позицию float left, а ссылки принимали значения float right, но ссылки не принимают этого значенияЯ...

148