Java。从不适合字节边界的字节数组中的位中提取整数
Java. Extracting integers from bits in a byte array not fitting the byte boundary
我有以下字节数组:
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 秒到一分钟才能提取出来。
这里我有点不知所措。如何使用按位运算符执行此操作?
非常感谢!
我做了第一组,第二组也可以用类似的方式做
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 位)进行编码。所以我不得不把每一位都拿走 "construct" 从他们那里得到 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 位
尝试 运行 代码并读取输出。
老实说,我不确定这是否是最好的方法,但我相信它至少比处理字符串要快
I assume you have an understanding of the basic bit operations and how to express them in 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 的最少四位,然后用 space 为字节 2 中的位 space =18=],用 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
表示的整数。
它returns提取的整数个数。
例如原题可解为
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;
}
}
我有以下字节数组: 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 秒到一分钟才能提取出来。
这里我有点不知所措。如何使用按位运算符执行此操作?
非常感谢!
我做了第一组,第二组也可以用类似的方式做
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 位)进行编码。所以我不得不把每一位都拿走 "construct" 从他们那里得到 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 位
尝试 运行 代码并读取输出。
老实说,我不确定这是否是最好的方法,但我相信它至少比处理字符串要快
I assume you have an understanding of the basic bit operations and how to express them in 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 的最少四位,然后用 space 为字节 2 中的位 space =18=],用 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
表示的整数。
它returns提取的整数个数。
例如原题可解为
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;
}
}