Reputation: 21389
I am having some difficulty with these two functions: byteArrayToInt
and intToByteArray
.
The problem is that if I use one to get to another and that result to get to the former, the results are different, as you can see from my examples below.
I cannot find the bug in the code. Any ideas are very welcome. Thanks.
public static void main(String[] args)
{
int a = 123;
byte[] aBytes = intToByteArray(a);
int a2 = byteArrayToInt(aBytes);
System.out.println(a); // prints '123'
System.out.println(aBytes); // prints '[B@459189e1'
System.out.println(a2); // prints '2063597568
System.out.println(intToByteArray(a2)); // prints '[B@459189e1'
}
public static int byteArrayToInt(byte[] b)
{
int value = 0;
for (int i = 0; i < 4; i++) {
int shift = (4 - 1 - i) * 8;
value += (b[i] & 0x000000FF) << shift;
}
return value;
}
public static byte[] intToByteArray(int a)
{
byte[] ret = new byte[4];
ret[0] = (byte) (a & 0xFF);
ret[1] = (byte) ((a >> 8) & 0xFF);
ret[2] = (byte) ((a >> 16) & 0xFF);
ret[3] = (byte) ((a >> 24) & 0xFF);
return ret;
}
Upvotes: 48
Views: 155950
Reputation: 93948
That's a lot of work for:
public static int byteArrayToLeInt(byte[] b) {
final ByteBuffer bb = ByteBuffer.wrap(b);
bb.order(ByteOrder.LITTLE_ENDIAN);
return bb.getInt();
}
public static byte[] leIntToByteArray(int i) {
final ByteBuffer bb = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE);
bb.order(ByteOrder.LITTLE_ENDIAN);
bb.putInt(i);
return bb.array();
}
This method uses the Java ByteBuffer
and ByteOrder
functionality in the java.nio
package. This code should be preferred where readability is required. It should also be very easy to remember.
I've shown Little Endian byte order here. To create a Big Endian version you can simply leave out the call to order(ByteOrder)
.
In code where performance is higher priority than readability (about 10x as fast):
public static int byteArrayToLeInt(byte[] encodedValue) {
int value = (encodedValue[3] << (Byte.SIZE * 3));
value |= (encodedValue[2] & 0xFF) << (Byte.SIZE * 2);
value |= (encodedValue[1] & 0xFF) << (Byte.SIZE * 1);
value |= (encodedValue[0] & 0xFF);
return value;
}
public static byte[] leIntToByteArray(int value) {
byte[] encodedValue = new byte[Integer.SIZE / Byte.SIZE];
encodedValue[3] = (byte) (value >> Byte.SIZE * 3);
encodedValue[2] = (byte) (value >> Byte.SIZE * 2);
encodedValue[1] = (byte) (value >> Byte.SIZE);
encodedValue[0] = (byte) value;
return encodedValue;
}
Just reverse the byte array index to count from zero to three to create a Big Endian version of this code.
Notes:
Integer.BYTES
constant, which is more succinct than Integer.SIZE / Byte.SIZE
.Upvotes: 51
Reputation: 5403
Instead of allocating space, et al, an approach using ByteBuffer
from java.nio
....
byte[] arr = { 0x01, 0x00, 0x00, 0x00, 0x48, 0x01};
// say we want to consider indices 1, 2, 3, 4 {0x00, 0x00, 0x00, 0x48};
ByteBuffer bf = ByteBuffer.wrap(arr, 1, 4); // big endian by default
int num = bf.getInt(); // 72
Now, to go the other way.
ByteBuffer newBuf = ByteBuffer.allocate(4);
newBuf.putInt(num);
byte[] bytes = newBuf.array(); // [0, 0, 0, 72] {0x48 = 72}
Upvotes: -1
Reputation: 105
I found a simple way in com.google.common.primitives which is in the [Maven:com.google.guava:guava:12.0.1]
long newLong = Longs.fromByteArray(oldLongByteArray);
int newInt = Ints.fromByteArray(oldIntByteArray);
Have a nice try :)
Upvotes: 2
Reputation: 1
/*sorry this is the correct */
public byte[] IntArrayToByteArray(int[] iarray , int sizeofintarray)
{
final ByteBuffer bb ;
bb = ByteBuffer.allocate( sizeofintarray * 4);
for(int k = 0; k < sizeofintarray ; k++)
bb.putInt(k * 4, iar[k]);
return bb.array();
}
Upvotes: 0
Reputation: 8424
I like owlstead's original answer, and if you don't like the idea of creating a ByteBuffer
on every method call then you can reuse the ByteBuffer
by calling it's .clear()
and .flip()
methods:
ByteBuffer _intShifter = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE)
.order(ByteOrder.LITTLE_ENDIAN);
public byte[] intToByte(int value) {
_intShifter.clear();
_intShifter.putInt(value);
return _intShifter.array();
}
public int byteToInt(byte[] data)
{
_intShifter.clear();
_intShifter.put(data, 0, Integer.SIZE / Byte.SIZE);
_intShifter.flip();
return _intShifter.getInt();
}
Upvotes: 2
Reputation: 4565
You can also use BigInteger for variable length bytes. You can convert it to Long, Integer or Short, whichever suits your needs.
new BigInteger(bytes).intValue();
or to denote polarity:
new BigInteger(1, bytes).intValue();
To get bytes back just:
new BigInteger(bytes).toByteArray()
Upvotes: 24
Reputation: 53521
Your methods should be (something like)
public static int byteArrayToInt(byte[] b)
{
return b[3] & 0xFF |
(b[2] & 0xFF) << 8 |
(b[1] & 0xFF) << 16 |
(b[0] & 0xFF) << 24;
}
public static byte[] intToByteArray(int a)
{
return new byte[] {
(byte) ((a >> 24) & 0xFF),
(byte) ((a >> 16) & 0xFF),
(byte) ((a >> 8) & 0xFF),
(byte) (a & 0xFF)
};
}
These methods were tested with the following code :
Random rand = new Random(System.currentTimeMillis());
byte[] b;
int a, v;
for (int i=0; i<10000000; i++) {
a = rand.nextInt();
b = intToByteArray(a);
v = byteArrayToInt(b);
if (a != v) {
System.out.println("ERR! " + a + " != " + Arrays.toString(b) + " != " + v);
}
}
System.out.println("Done!");
Upvotes: 60
Reputation: 10266
I took a long look at many questions like this, and found this post... I didn't like the fact that the conversion code is duplicated for each type, so I've made a generic method to perform the task:
public static byte[] toByteArray(long value, int n)
{
byte[] ret = new byte[n];
ret[n-1] = (byte) ((value >> (0*8) & 0xFF);
ret[n-2] = (byte) ((value >> (1*8) & 0xFF);
...
ret[1] = (byte) ((value >> ((n-2)*8) & 0xFF);
ret[0] = (byte) ((value >> ((n-1)*8) & 0xFF);
return ret;
}
See full post.
Upvotes: 0
Reputation: 1716
here is my implementation
public static byte[] intToByteArray(int a) {
return BigInteger.valueOf(a).toByteArray();
}
public static int byteArrayToInt(byte[] b) {
return new BigInteger(b).intValue();
}
Upvotes: -2
Reputation: 54796
You're swapping endianness between your two methods. You have intToByteArray(int a)
assigning the low-order bits into ret[0]
, but then byteArrayToInt(byte[] b)
assigns b[0]
to the high-order bits of the result. You need to invert one or the other, like:
public static byte[] intToByteArray(int a)
{
byte[] ret = new byte[4];
ret[3] = (byte) (a & 0xFF);
ret[2] = (byte) ((a >> 8) & 0xFF);
ret[1] = (byte) ((a >> 16) & 0xFF);
ret[0] = (byte) ((a >> 24) & 0xFF);
return ret;
}
Upvotes: 44