Link to home
Start Free TrialLog in
Avatar of welsh_boy
welsh_boy

asked on

Sending A Long in a byte Array

I am trying to send a Long value that represents a filesize into a 128 byte data packet, the first byte is a header then I have reserved the next 8 bytes for the filesize.

I have done some research and found a class called BigInteger
http://java.sun.com/j2se/1.4.2/docs/api/java/math/BigInteger.html
that does this.

My problem is knowing how many of the bytes to read back off at the other side, as If I read all 8 on a long value that doesnt fill all 8 then I get a wrong value, here is my code.

-------------
//Create Byte array and append to packet
     BigInteger big = new BigInteger(Long.toString(fileLength));
     byte[] testlong = new byte[8];
     testlong =  big.toByteArray();
     String dickString = new String(testlong);
     System.out.println(big.longValue() );//test to see if its seding the right value

     //Copy to the packet
     System.arraycopy(testlong, 0, testbuffer, 1, 8);
     // I get an arrayindex Out Of Bounds error here




------------
//Read from packet

     byte[] fileSize = new byte[8];
     //read back the 8 bytes from the data packet
     System.arraycopy(testbuffer, 1, fileSize, 0, 8);
     BigInteger big2 = new BigInteger(fileSize);
     System.out.println(big2.longValue() );


I can get it working with a small number eg 352, but I have to use 2 bytes instead of 8 to avoid the outofbounds exception.


Appreciate any help
Avatar of CEHJ
CEHJ
Flag of United Kingdom of Great Britain and Northern Ireland image

Try

BigInteger big = new BigInteger.valueOf(fileLength);
     testlong =  big.toByteArray();
     System.out.println(big.longValue() );//test to see if its seding the right value
     //Copy to the packet
     System.arraycopy(testlong, 0, testbuffer, 0, 8);
Sorry:

     BigInteger big = new BigInteger.valueOf(fileLength);
     byte[] testlong =  big.toByteArray();
     System.out.println(big.longValue() );//test to see if its sending the right value
     //Copy to the packet
     System.arraycopy(testlong, 0, testbuffer, 0, 8);
LOL, and the second index should be 1, not 0 (just saw the thing about the header). Make sure testbuffer.length >= 9
Use of BigInteger is a bit slow and unecessary.

You can use bit manipulation to handle converting bytes into long.
Here's an example of how to convert 4 bytes into an int, doing it for a long is a simple extension:
      int ch1 = buf[0]
      int ch2 = buf[1];
      int ch3 = buf[2];
      int ch4 = buf[3];
                int = return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));

Or alternatively use a DataInputStream wrapping a ByteArrayInputStream to handle it for you:

DataInputStream in = new DataInputStream(new ByteArrayInputStream(buf));
long l = in.readLong();
Similiar techniques can also be used for going the other direction.
It's only slow if it's perceptibly slow - and it almost certainly won't be. It's certainly more elegant and clearer.
More elegant and clear than:

long l = in.readLong();

I don't think so :)
I was talking about your first suggestion
Avatar of welsh_boy
welsh_boy

ASKER

Here is my ammended code, I am still getting the error

--

//Declare the Data Packet
      byte [] testbuffer=new byte [128];
//Set Header
        testbuffer[0]=PacketCode.SFT;
//Copy File name at byte[9]
      System.arraycopy(tester, 0, testbuffer, 9, tester.length);



     BigInteger big = new BigInteger(Long.toString(fileLength));
     byte[] testlong =  big.toByteArray();
     System.out.println("Long Send to Packet : " + big.longValue() );//test to see if its sending the right value
     //Copy to the packet at position 1 - 8
     System.arraycopy(testlong, 0, testbuffer, 1, 8); //<-- I get an out of bounds error here
     
     
//Read back long from the packet array

//Set up and empty 8 byte array
     byte[] fileSize = new byte[8];
//Copy long back from the byte array pos 1-8
     System.arraycopy(testbuffer, 1, fileSize, 0, 8);
     BigInteger big2 = new BigInteger(fileSize);
     System.out.println("Read Long from Data Packet: " + big2.longValue() );
DataOuputStream out = new DataOutputStream(new ByteArrayOutputStream(128));
out.writeByte(PacketCode.SFT);
out.writeLong(fileLength);
out.write(tester);
byte [] testbuffer= out.toByteArray();
And reading it back:

DataInputStream in = new DataInputStream(new ByteArrayInputStream(testbuffer));
byte packet = in.readByte();
long fileLength = in.readLong();
ASKER CERTIFIED SOLUTION
Avatar of CEHJ
CEHJ
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
> byte[] testlong =  big.toByteArray();

This will not necessarily return an 8 byte buffer. If you want to use this approach you will need to do:

System.arraycopy(testlong, 0, testbuffer, 1, testlong.length);
Actually thats not right either, should be:

System.arraycopy(testlong, 0, testbuffer, 1+(8-testlong.length), testlong.length);

Lot simpler to use DataOutput :)
cheers objects but the DataOutputStream doesnt seem to have a toByteArray() method
Im running Java 1.31

I have looked for the javadocs
http://java.sun.com/j2se/1.3/ja/docs/ja/api/java/io/DataOutputStream.html

any ideas??
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
thanks objects an CEHJ

Decided to go with the DataOuputStream method, It is a lot more efficient

Thanks for the lesson!
>>Decided to go with the DataOuputStream method, It is a lot more efficient

I agree. And objects is right about the toByteArray method of BigInteger: if there are leading zeros in the long, they won't be represented by empty array elements - they'll simply be omitted. There really should be a toLongByteArray method or something returning all 8 bytes.