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