1

I am wondering how can I turn my 32 character int into a 32-byte array as it is represented.

Example:

I have this int:

int test = 123456789;

And I want to turn it into this:

byte[] Write_Page_Four = new byte[] {  

                                (byte) 0x00, (byte) 0x00,
                                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
                                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
                                (byte) 0x00, (byte) 0x01, (byte) 0x23, (byte) 0x45,
                                (byte) 0x67, (byte) 0x89};

Currently, I'm thinking of splitting my int by 2 and just manually assigning them to the byte array but I am having some troubles in doing so, and I believe that this is not the best practice for my problem.

This is what I have ATM, which is returning error and still work on progress though and I could use some advice on it:

String test2 = "01";
String test1 = "0x"+test2; 
byte test =  Byte.valueOf(test1);
System.out.println("teeeeest-----"+test);

byte[] Write_Page_Four = new byte[] {(byte) test};

And this one is returning an error:

java.lang.NumberFormatException: For input string: "0x01"

makingitwork
  • 149
  • 2
  • 9
  • 2
    This number is way too large to be represented by an `int` (32 bits). Apart from that, do you want to the `byte[]` to represent the text, or the bytes of the actual `int`? –  Dec 07 '15 at 15:15
  • @Paul ooops you're right, I should make it clear that only 9 digits of int would be use the rest of the leading numbers are 0. so sorry about that. – makingitwork Dec 07 '15 at 15:19

3 Answers3

3

What is causing problems

Byte.valueOf doesn't parse data like the Java compiler does: it expects as input as a decimal number.

What you can use however, is Byte.valueOf(String,int) with an arbitrary radix. In that case you can solve it using:

byte test =  Byte.valueOf(test2,16); //using test2, not test1

Mind that should not add "0x" in the front. Nevertheless this is an inefficient way to do this.

Ints are 32-bits, not 32-bytes

A second problem is that you state that you can store a number like 12345678901234567890123456789011 into an int. You cannot. An int has 32 bits. This means its representation is limited to more or less 2.1B. So I think you mean you store 12345678901234567890123456789011 in a String?

Number systems

Mind that the number 12345678901234567890123456789011 is not represented internally as (byte) 0x12, (byte) 0x34,... unless you are working with binary coded decimals. This is because a computer uses the binary number system (and thus groups bytes with the hexadecimal representation), whereas humans use the decimal representation. 123456789 for instance will be represented as 0x07,0x5B,0xCD 0x15.

Serializing an int (or other datastructure) using an array of bytes

You can convert an int (and other datatypes) into an array of bytes using this code:

ByteBuffer b = ByteBuffer.allocate(4);
b.putInt(test);
byte[] result = b.array(); //result will be 4 bytes,
//since you can represent any int with four bytes.

Or, in case you want to represent the int like the way you do this, you could use the following method:

int t = test;
byte[] dat = new byte[5];//at most 5 bytes needed
for(int j = 4; test != 0; j--) {
    int rm = t%100;
    dat[j] = (byte) (rm%10+((rm/10)<<8));
    t /= 100;
}
//result is dat
Community
  • 1
  • 1
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • @makingitwork: still it is not completely clear. Mind that a byte represents numbers between `0` and (including) `255`. So you can represent it more effeciently (and a computer does this, because it makes additions, etc. more efficient as well). `123456789` is for instance the equivalent of `0x75bcd15`. – Willem Van Onsem Dec 07 '15 at 15:25
  • What would your suggested solution be for this kind of problem? – makingitwork Dec 07 '15 at 15:26
  • I meant the confusion regarding the whole int value, I did miss that :D, regarding my question as stated I want to be able to present my int value into a byte value as is, that is why I tried appending 0x to my int, I do understand that converting string to byte will result in a very different outcome as each character has a different byte representation. that is why I was hoping that I could simply append 0x to my number and make it look like a byte data already. – makingitwork Dec 07 '15 at 15:33
  • @makingitwork: well string manipulations are tend to be very inefficient. In order to serialize an `int` to a `byte[]` I recommend using the `ByteBuffer` or Andreas's solution (which is semantically equivalent). It will result in a fixed number of bits and a smaller number of bits. Furthermore it prevents one from *reinventing the wheel*. – Willem Van Onsem Dec 07 '15 at 15:36
  • What I mean in my question is not to convert but to copy, took me a while to realize this. :D and I found this [link](http://stackoverflow.com/questions/8652804/how-to-convert-string-to-byte-in-java) though I cannot understand the answer. – makingitwork Dec 07 '15 at 15:43
2

Instead of processing the textual representation of the number I'd recommend to simply calculate the single numbers:

Get two digits of the number each time:

int inp = 1234...;

for(int lowerBound = 1 ; lowerBound < Integer.MAX_VALUE ; lowerBound *= 100)
    //twoDigit contains two digits of the input-number
    int twoDigit = (inp /lowerBound) % 100;

Transform these two digits into a byte:

byte transform(int i){
    if(i == 0)
        return 0x00;

    int lsd = (i % 10); //least significant digit of the input (decimal)
    int msd = (i / 10); //most significant digit

    //merge lsd and msd into a single number, where the lower 4 bits are reserved for
    //lsd and the higher 4 bits for msd
    return lsd | (msd << 4);
}

The complete code would look like this:

import java.util.Arrays;

public class test
{
    private static final int BYTES = 4;

    public static void main(String[] args){
        int v = 12345678;

        int at_arr = BYTES - 1;
        byte[] result = new byte[BYTES];//int is 32-bit/4 byte long

        for(int lowerBound = 1 ; lowerBound < Integer.MAX_VALUE && at_arr > -1; lowerBound *= 100, at_arr--)
            result[at_arr] = transformDigits((v / lowerBound) % 100);

        for(byte b : result)
            System.out.print(" 0x" + Integer.toString(b , 16) + ",");
        System.out.println();
    }

    static byte transformDigits(int i){
        if(i == 0)
            return 0x00;

        int lsd = (i % 10); //least significant digit of the input (decimal)
        int msd = (i / 10); //most significant digit

        //merge lsd and msd into a single number, where the lower 4 bits are reserved for
        //lsd and the higher 4 bits for msd
        return (byte) (lsd | (msd << 4));
    }
}

This code can be used basically for any integral type, if the types and value of BYTES are updated appropriately.

  • Mind that the OP is having trouble between number systems. `1234...` will not generate `0x12,0x34,...` simply because it is interpreted decimally whereas the OP wants to interpret it hexadecimally. +1 nevertheless. – Willem Van Onsem Dec 07 '15 at 15:19
  • @CommuSoft OP wants to transform an `int` into the raw bytes representing it. I just presented a **way** more efficient way to do this transformation than converting to text and parsing back. –  Dec 07 '15 at 15:21
  • What would be a non-lazy way of doing this? as I plan to implement a satisfactory solution, not a duct tape solution. – makingitwork Dec 07 '15 at 15:25
  • @makingitwork i think i understood the question now. I'll edit the post, my solution won't even work for what you want. –  Dec 07 '15 at 15:28
  • @makingitwork sry for the bugs, ive corrected everything, the final version has correct output. Except for the fact that the output doesn't exactly look nice and `0x00` is outputted as `0x0`. –  Dec 07 '15 at 15:51
  • In this part of the code `for(byte b : result) System.out.print(" 0x" + Integer.toString(b , 16) + ",");` I changed it to: `for(byte b : result){ tarr[x] = "0x" + Integer.toString(b , 16); System.out.println(tarr[x]); x++; }` and I got a nullpointerexception error at the array part. i declared the array as `String[] tarr = null;` – makingitwork Dec 07 '15 at 16:11
  • @makingitwork if `tarr` is `null`, you can't assign anything to it. And why would you even need a `String[]` anyways? Either use `String[] tarr = new String[BYTES];` or leave the `String[]` completely away. –  Dec 07 '15 at 16:36
2

Here's how to convert an int to a byte[]:

int test = 123456789;

byte[] bytes = new byte[4];
bytes[0] = (byte)(test >> 24);
bytes[1] = (byte)(test >> 16);
bytes[2] = (byte)(test >> 8);
bytes[3] = (byte)test;

System.out.printf("%02x %02x %02x %02x%n", bytes[0], bytes[1], bytes[2], bytes[3]);

Output

07 5b cd 15

You can also inline it, if you want:

int test = 123456789;
byte[] bytes = new byte[] { (byte)(test >> 24),
                            (byte)(test >> 16),
                            (byte)(test >> 8),
                            (byte)test };
System.out.printf("%02x %02x %02x %02x%n", bytes[0], bytes[1], bytes[2], bytes[3]);
Andreas
  • 154,647
  • 11
  • 152
  • 247
  • This is indeed how you *should* serialize an `int`. The problem is that the OP seems to have a different format in mind. +1 anyway. – Willem Van Onsem Dec 07 '15 at 15:34
  • @CommuSoft Yeah, that's why I show the result, since it deviates from question. You got my +1 for providing both an easier version of this, and an alternate following question more literally (even though that makes little sense to me). – Andreas Dec 07 '15 at 15:37