179

I want to store some data into byte arrays in Java. Basically just numbers which can take up to 2 Bytes per number.

I'd like to know how I can convert an integer into a 2 byte long byte array and vice versa. I found a lot of solutions googling but most of them don't explain what happens in the code. There's a lot of shifting stuff I don't really understand so I would appreciate a basic explanation.

4
  • 4
    How much do you understand about bit shifting? It sounds like the question is really "what does bit shifting do" more than about the conversion to byte arrays, really - if you actually want to understand how the conversion would work. Commented Oct 1, 2011 at 8:20
  • 1
    (Just to clarify, I'm fine with either question, but it's worth making it clear which question you really want answered. You're likely to get an answer which is more useful to you that way.) Commented Oct 1, 2011 at 8:21
  • Okay i got your point! Thanks for the remark. I know what bit shifting does i just didn't understand what its used for in converting byte arrays yet. Commented Oct 2, 2011 at 12:23
  • 3
    @prekageo and Jeff Mercado Thanks for your two answers. prekageo gave a good explanation of how this is done, nice link! That makes it a lot clearer to me. And Jeff Mercados solution solved the problem i had. Commented Oct 2, 2011 at 12:28

9 Answers 9

268

Use the classes found in the java.nio namespace, in particular, the ByteBuffer. It can do all the work for you.

byte[] arr = { 0x00, 0x01 };
ByteBuffer wrapped = ByteBuffer.wrap(arr); // big-endian by default
short num = wrapped.getShort(); // 1

ByteBuffer dbuf = ByteBuffer.allocate(2);
dbuf.putShort(num);
byte[] bytes = dbuf.array(); // { 0, 1 }
Sign up to request clarification or add additional context in comments.

6 Comments

Is it too expensive if the byte array contains only 1 or 2 integer? Not sure about the cost constructing a ByteBuffer.
How often are you working with binary data in 2-4 byte chunks? Really? A sane implementation would either work with it in BUFSIZ chunks (typically 4kb) or use other IO libraries that hides this detail. There's an entire library within the framework that's dedicated to help you work on buffers of data. You do a disservice to yourself and other maintainers of your code when you implement common operations without good reason (be it perf or other critical operation). These buffers are merely wrappers that operates on arrays, nothing more.
How come you can instantiate an abstract class?
@JaveneCPPMcGowan There is no direct instantiation present in this answer. If you mean the factory methods wrap and allocate, they don't return an instance of the abstract class ByteBuffer.
Not a solution for 3 byte stride. We can get Char, Short, Int. I suppose I could pad to 4 bytes and discard the 4th each time, but I would rather not.
|
157
byte[] toByteArray(int value) {
     return  ByteBuffer.allocate(4).putInt(value).array();
}

byte[] toByteArray(int value) {
    return new byte[] { 
        (byte)(value >> 24),
        (byte)(value >> 16),
        (byte)(value >> 8),
        (byte)value };
}

int fromByteArray(byte[] bytes) {
     return ByteBuffer.wrap(bytes).getInt();
}
// packing an array of 4 bytes to an int, big endian, minimal parentheses
// operator precedence: <<, &, | 
// when operators of equal precedence (here bitwise OR) appear in the same expression, they are evaluated from left to right
int fromByteArray(byte[] bytes) {
     return bytes[0] << 24 | (bytes[1] & 0xFF) << 16 | (bytes[2] & 0xFF) << 8 | (bytes[3] & 0xFF);
}

// packing an array of 4 bytes to an int, big endian, clean code
int fromByteArray(byte[] bytes) {
     return ((bytes[0] & 0xFF) << 24) | 
            ((bytes[1] & 0xFF) << 16) | 
            ((bytes[2] & 0xFF) << 8 ) | 
            ((bytes[3] & 0xFF) << 0 );
}

When packing signed bytes into an int, each byte needs to be masked off because it is sign-extended to 32 bits (rather than zero-extended) due to the arithmetic promotion rule (described in JLS, Conversions and Promotions).

There's an interesting puzzle related to this described in Java Puzzlers ("A Big Delight in Every Byte") by Joshua Bloch and Neal Gafter . When comparing a byte value to an int value, the byte is sign-extended to an int and then this value is compared to the other int

byte[] bytes = (…)
if (bytes[0] == 0xFF) {
   // dead code, bytes[0] is in the range [-128,127] and thus never equal to 255
}

Note that all numeric types are signed in Java with exception to char being a 16-bit unsigned integer type.

7 Comments

I think the & 0xFFs are unnecessary.
@LeifEricson I believe the & 0xFFs are necessary as it tells the JVM to convert the signed byte into an integer with just those bits set. Otherwise the byte -1 (0xFF) will turn into the int -1 (0xFFFFFFFF). I could be wrong and even if I am it doesn't hurt and makes things clearer.
& 0xFF is mandatory indeed. byte b = 0; b |= 0x88; System.out.println(Integer.toString(b, 16)); //Output: -78 System.out.println(Integer.toString(b & 0xFF, 16)); //Output: 88
@ptntialunrlsd Not actually. Before you performing & operation on byte with 0xFF (int), JVM will cast the byte to int with 1 extended or 0 extended according the the leading bit first. There's no unsigned byte in Java, bytes are always signed.
When parse int from byte array, pay attention to the size of the byte array, if it's greater than 4 bytes, according to the doc of ByteBuffer.getInt() : Reads the next four bytes at this buffer's current position , only the first 4 bytes will be parsed, which should not be what you want.
|
75

You can also use BigInteger for variable length bytes. You can convert it to long, int 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()

Although simple, I just wanted to point out that if you run this many times in a loop, this could lead to a lot of garbage collection. This may be a concern depending on your use case.

1 Comment

Note that since 1.8, it's intValueExact, not intValue
6

A basic implementation would be something like this:

public class Test {
    public static void main(String[] args) {
        int[] input = new int[] { 0x1234, 0x5678, 0x9abc };
        byte[] output = new byte[input.length * 2];

        for (int i = 0, j = 0; i < input.length; i++, j+=2) {
            output[j] = (byte)(input[i] & 0xff);
            output[j+1] = (byte)((input[i] >> 8) & 0xff);
        }

        for (int i = 0; i < output.length; i++)
            System.out.format("%02x\n",output[i]);
    }
}

In order to understand things you can read this WP article: http://en.wikipedia.org/wiki/Endianness

The above source code will output 34 12 78 56 bc 9a. The first 2 bytes (34 12) represent the first integer, etc. The above source code encodes integers in little endian format.

Comments

5
/** length should be less than 4 (for int) **/
public long byteToInt(byte[] bytes, int length) {
        int val = 0;
        if(length>4) throw new RuntimeException("Too big to fit in int");
        for (int i = 0; i < length; i++) {
            val=val<<8;
            val=val|(bytes[i] & 0xFF);
        }
        return val;
    }

Comments

5

As often, guava has what you need.

To go from byte array to int: Ints.fromBytesArray, doc here

To go from int to byte array: Ints.toByteArray, doc here

Comments

2

Without using any external or obscure library or applying bitwise magic (bit difficult to read), you can use ByteArrayOutputStream combined with DataOutputStream to write an int into the stream like this using it's writeInt(int) method:

// assuming num is of type int that we want to convert into byte[]
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
dos.writeInt(num);
byte[] intBytes = bos.toByteArray();
bos.close();

Similarly use ByteArrayInputStream combined with DataInputStream to read an int from the stream like this using it's int readInt() method:

// assuming byteArr is of type byte[] that contains a number we need to read
ByteArrayInputStream bis = new ByteArrayInputStream(byteArr);
DataInputStream dis = new DataInputStream(bis);
int num = dis.readInt();
bis.close();

Update: If integer number is small enough to be fit into 2 bytes only then use writeShort and readShort methods instead of writeInt and readInt methods.

2 Comments

One of the main points of my question (back in the days) was storing an integer in a byte array so that it will take up only two bytes if the value is low enough. I didn't try it but looking at this solution intuitively i would say that readInt and writeInt are fixed to integer length.
@Chris: There is a writeShort method available as well if you know that your numbers is small enough to be fit in 2 bytes only. Please see updated answer as well.
0

Someone with a requirement where they have to read from bits, lets say you have to read from only 3 bits but you need signed integer then use following:

data is of type: java.util.BitSet

new BigInteger(data.toByteArray).intValue() << 32 - 3 >> 32 - 3

The magic number 3 can be replaced with the number of bits (not bytes) you are using.

Comments

-7

i think this is a best mode to cast to int

   public int ByteToint(Byte B){
        String comb;
        int out=0;
        comb=B+"";
        salida= Integer.parseInt(comb);
        out=out+128;
        return out;
    }

first comvert byte to String

comb=B+"";

next step is comvert to a int

out= Integer.parseInt(comb);

but byte is in rage of -128 to 127 for this reasone, i think is better use rage 0 to 255 and you only need to do this:

out=out+256;

5 Comments

This is wrong. Consider the byte 0x01. Your method will output 129 which is wrong. 0x01 should output the integer 1. You should only add 128 if the integer that you get from parseInt is negative.
I meant you should add 256 not 128. Couldn't edit it afterwards.
changed post to add the 256 as it may be useful to others!
This does a lot of casting and create new objects (think doing this on for loops) that can degrade the performance, please check the Integer.toString() method for hints about how to parse numbers.
also, when posting code on stackoverflow the point is to post code that easily makes sense. Code that easily makes sense must have understandable identifiers. And on stackoverflow, understandable necessarily means in English.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.