tags:

views:

391

answers:

6

I am reading 8 bytes of data in from a hardware device. I need to convert them into a numeric value. I think I want to convert them to a long as that should fit 8 bytes. I am not very familiar with Java and low level data type operations. I seem to have two problems (apart from the fact there is almost no documentation for the hardware in question), The bytes are expecting to be unsigned, so I can't do a straight integer conversion. I am not sure what endianness they are.

Any advice would be appreciated.


Ended up with this (taken from some source code I probably should have read a week ago):

public static final long toLong (byte[] byteArray, int offset, int len)
{
   long val = 0;
   len = Math.min(len, 8);
   for (int i = (len - 1); i >= 0; i--)
   {
      val <<= 8;
      val |= (byteArray [offset + i] & 0x00FF);
   }
   return val;
}
A: 

Byte#longValue() should do it

And if not (thanks for the source example) you can use java.nio.ByteBuffer such as in

 public static long toLong(byte[] b) {
    ByteBuffer bb = ByteBuffer.allocate(b.length);
    bb.put(b);
    return bb.getLong();
}

The initial order is BIG_ENDIAN you can reed more here

DroidIn.net
I had something like that but it was still no good. Maybe it's because I am new to Java though. public static long bufferToLong (byte[] b) { long value = b[0]; for (int i=1;i<b.length;++i) { Byte v = new Byte(b[i]); value += Math.pow(0xFF, i+1) * v.longValue(); } return value; }
Jotham
So what's the -1 for? Anyways - I extended the answer to give you maybe another idea. From what I know - java.nio is pretty fast (faster than your regular variety streams)
DroidIn.net
+1  A: 

For the endianness, test with some numbers you know, and then you will be using a byte shifting to move them into the long.

You may find this to be a starting point. http://www.janeg.ca/scjp/oper/shift.html

The difficulty is that depending on the endianess will change how you do it, but you will shift by 24, 16, 8 then add the last one, basically, if doing 32 bits, but you are going longer, so just do extra shifting.

James Black
With extra shifting, you have to watch out that you are shifting a `long`, not an `int`, because shifting more than 24 bits in an `int` will discard the highest order bits.
erickson
He stated it was a long, so I figure he can determine how many bits it should be that he really needs.
James Black
A: 

Take a look at BigInteger(byte[]). It is almost what you want except that it is a signed one. So you may add one more byte to it before you pass it on to BigInteger.

Another thing is that you should be aware of what endian your bytes are.

Hope this helps.

NawaMan
+3  A: 
byte[] buf = new byte[8];
/* Fill buf somehow... */
long l = ((buf[0] & 0xFFL) << 56) |
         ((buf[1] & 0xFFL) << 48) |
         ((buf[2] & 0xFFL) << 40) |
         ((buf[3] & 0xFFL) << 32) |
         ((buf[4] & 0xFFL) << 24) |
         ((buf[5] & 0xFFL) << 16) |
         ((buf[6] & 0xFFL) <<  8) |
         ((buf[7] & 0xFFL) <<  0) ;
erickson
You might want to put a few casts to long in there...
Tom Hawtin - tackline
And perhaps use an array index other than 0.
Tom Hawtin - tackline
Yeah, I noticed that as you were commenting... I took care of it by promoting to long in the masking.
erickson
+2  A: 

I believe that you could benefit from using java.nio. This is how you can store 8 bytes in a long:

// Byte Array TO Long
public static long batol(byte[] buff) {
    return batol(buff, false);
}

public static long batol(byte[] buff, boolean littleEndian) {
    assert(buff.length == 8);
    ByteBuffer bb = ByteBuffer.wrap(buff);
    if (littleEndian) bb.order(ByteOrder.LITTLE_ENDIAN);
    return bb.getLong();
}

Of course, the resulting longs will have signed representation, but they will have identical binary values to the source data. For a 64 bit+ unsigned representation and arithmatic, you'll need to use BigInteger. Here's how to convert from "unsigned" data stored in a long to a correct BigInteger:

// "Unsigned" Long TO Big Integer
public static BigInteger ultobi(long ul) {
    byte[] buff = new byte[8];
    ByteBuffer.wrap(buff).asLongBuffer().put(ul);
    return new BigInteger(+1, buff);
}
Gunslinger47
A: 

If you're reading from an InputStream, you may also want to look at DataInputStream.readLong(). Java 1.5 introduced Long.reverseBytes(long) which may help you with endianness.

McDowell