Getting bits from bytes

For example, there are 8 bytes of data. There is a starting byte and a starting bit - where you need to get the information, as well as the length in bits(how much you need to take).

How can I get from these 8 bytes for example, from the first byte - 7 and 8 bits (i.e. starting byte #1, starting bit position #7, length 2 bits)

Or for example, from the 3rd bit of the second byte, take 14 bits (that is, the second and third bytes are used)

Author: DuosDuo, 2018-08-01

3 answers

In order not to "fight" with bit operations yourself, you can use the standard class 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);
}

And usage:

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


In BitSet, the bit indexes are defined as:

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

If you need the reverse order:

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

Then, as an option, you can pre-change the order of bits in bytes:

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

Basically, in this case, the "take the bits manually" solution becomes shorter and simpler:

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;
}
 6
Author: Regent, 2018-08-01 10:58:08

How it works "under the hood":

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));
}
 3
Author: ArtemLP, 2018-08-03 07:59:47

Use the bitwise 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 в двоичном коде 

Result:

true
true
 0
Author: GreyGoblin, 2018-08-01 06:33:45