我有以下字节数组: 01010110 01110100 00100101 01001011
这些字节分为两组,用于编码七个整数。我知道第一组由3个值组成,每个值4位(0101 0110 0111),代表数字5,6,7。第二组由4个值组成,每个值为5位(01000 01001 01010 01011),表示整数8,9,10和11。
要提取整数,我目前正在使用以下方法。将数组转换为二进制字符串:
public static String byteArrayToBinaryString(byte[] byteArray)
{
String[] arrayOfStrings = new String[byteArray.length];
for(int i=0; i<byteArray.length; i++)
{
arrayOfStrings[i] = byteToBinaryString(byteArray[i]);
}
String bitsetString = "";
for(String testArrayStringElement : arrayOfStrings)
{
bitsetString += testArrayStringElement;
}
return bitsetString;
}
// Taken from here: http://helpdesk.objects.com.au/java/converting-large-byte-array-to-binary-string
public static String byteToBinaryString(byte byteIn)
{
StringBuilder sb = new StringBuilder("00000000");
for (int bit = 0; bit < 8; bit++)
{
if (((byteIn >> bit) & 1) > 0)
{
sb.setCharAt(7 - bit, '1');
}
}
return sb.toString();
}
然后,我将二进制字符串拆分为2个子字符串:12个字符和20个字符。然后我将每个子串分成新的子串,每个子串的长度等于位数。然后我将每个子子串转换为整数。
它可以工作,但代表数千个整数的字节数组需要30秒到一分钟才能提取。
我在这里有点不知所措。如何使用按位运算符执行此操作?
非常感谢!
答案 0 :(得分:2)
我假设您已经了解了基本bit operations以及如何用Java表达它们。
使用铅笔绘制问题的合成图片
byte 0 byte 1 byte 2 byte 3
01010110 01110100 00100101 01001011
\__/\__/ \__/\______/\___/\______/\___/
a b c d e f g
要提取 a , b 和 c ,我们需要执行以下操作
a b c
byte 0 byte 0 byte 1
01010110 01010110 01110100
\. \. |||||||| \. \.
'\ '\ XXXX|||| '\ '\
0.. 0101 0.. 0110 0.. 0111
Shift And Shift
在Java中
int a = byteArray[0] >>> 4, b = byteArray[0] & 0xf, c = byteArray[1] >>> 4;
其他值 d , e , f 和 g 的计算方法类似,但其中一些需要从数组中读取两个字节(实际上是 d 和 f )。
d e
byte 1 byte 2 byte 2
01110100 00100101 00100101
||||\\\\ | |\\\\\
XXXX \\\\ | X \\\\\
\\\\| \\\\\
0.. 01000 01001
要计算 d ,我们需要用byteArray[1] & 0xf
隔离字节1的至少四位,然后用(byteArray[1] & 0xf) << 1
为字节2的位腾出空间,用byteArray[1] >>> 7
并最终将结果合并在一起。
int d = (byteArray[1] & 0xf) << 1 | byteArray[2] >>> 7;
int e = (byteArray[2] & 0x7c) >>> 2;
int f = (byteArray[2] & 0x3) << 3 | byteArray[3] >>> 5;
int g = byteArray[3] & 0x1f;
当您熟悉处理位操作时,您可以考虑概括提取整数的函数。
我创建了函数int extract(byte[] bits, int[] sizes, int[] res)
,它给出了一个字节bits
数组,一个大小为sizes
的数组,其中偶数索引保存整数的大小以提取比特和奇数索引要提取的整数,输出数组res
大到足以容纳输出中的所有整数,从bits
中提取sizes
表示的所有整数。
它返回提取的整数数。
例如原始问题可以解决为
int res[] = new int[8];
byte bits[] = new byte[]{0x56, 0x74, 0x25, 0x4b};
//Extract 3 integers of 4 bits and 4 integers of 5 bits
int ints = BitsExtractor.extract(bits, new int[]{4, 3, 5, 4}, res);
public class BitsExtractor
{
public static int extract(byte[] bits, int[] sizes, int[] res)
{
int currentByte = 0; //Index into the bits array
int intProduced = 0; //Number of ints produced so far
int bitsLeftInByte = 8; //How many bits left in the current byte
int howManyInts = 0; //Number of integers to extract
//Scan the sizes array two items at a time
for (int currentSize = 0; currentSize < sizes.length - 1; currentSize += 2)
{
//Size, in bits, of the integers to extract
int intSize = sizes[currentSize];
howManyInts += sizes[currentSize+1];
int temp = 0; //Temporary value of an integer
int sizeLeft = intSize; //How many bits left to extract
//Do until we have enough integer or we exhaust the bits array
while (intProduced < howManyInts && currentByte <= bits.length)
{
//How many bit we can extract from the current byte
int bitSize = Math.min(sizeLeft, bitsLeftInByte); //sizeLeft <= bitsLeftInByte ? sizeLeft : bitsLeftInByte;
//The value to mask out the number of bit extracted from
//The current byte (e.g. for 3 it is 7)
int byteMask = (1 << bitSize) - 1;
//Extract the new bits (Note that we extract starting from the
//RIGHT so we need to consider the bits left in the byte)
int newBits = (bits[currentByte] >>> (bitsLeftInByte - bitSize)) & byteMask;
//Create the new temporary value of the current integer by
//inserting the bits in the lowest positions
temp = temp << bitSize | newBits;
//"Remove" the bits processed from the byte
bitsLeftInByte -= bitSize;
//Is the byte has been exhausted, move to the next
if (bitsLeftInByte == 0)
{
bitsLeftInByte = 8;
currentByte++;
}
//"Remove" the bits processed from the size
sizeLeft -= bitSize;
//If we have extracted all the bits, save the integer
if (sizeLeft == 0)
{
res[intProduced++] = temp;
temp = 0;
sizeLeft = intSize;
}
}
}
return intProduced;
}
}
答案 1 :(得分:1)
我做了第一组,第二组可以用类似的方式完成
public static void main(String args[]) {
//an example 32 bits like your example
byte[] bytes = new byte[4];
bytes[0] = 31;//0001 1111
bytes[1] = 54;//0011 0110
bytes[2] = 67;
bytes[3] = 19;
//System.out.println(bytes[0]);
int x = 0;
int j = -1; // the byte number
int k = 0; // the bit number in that byte
int n = 0; // the place of the bit in the integer we are trying to read
for (int i = 0; i < 32; i++) {
if (i < 12) { //first group
if (i % 8 == 0) {
j++;
k = 0;
}
if (i % 4 == 0) {
x = 0;
n = 0;
}
byte bit = (byte) ((bytes[j] & (1 << (7 - k))) >> (7 - k));
System.out.println("j is :" + j + " k is :" + k + " " + bit);
x = x | bit << (3 - n);
if ((i + 1) % 4 == 0) {
System.out.println(x);
}
k++;
n++;
} else {
}
}
}
这有点棘手,因为你试图编码一个小于java分配的整数(8位)。所以我不得不采取每一点并“构造”他们的int
获得每一位
byte bit = (byte) ((bytes[j] & (1 << (7 - k))) >> (7 - k));
这将获取我们所在的字节并执行And
操作。例如,我想要第一个字节的第3位,我做
bytes[0] & 1 << (7 - 3)
但是这给了我一个超过8位的整数,所以我仍然需要将它移位以获得>> (7 - 3)
然后我只用Or
x
(我们试图解码的int)。用<< (3 - n)
将它放在正确的位置。 3因为你的整数是用4位编码的
尝试运行代码并阅读输出。
老实说,我不确定这是否是最佳方式,但我相信它至少比处理字符串更快