TheLQ
TheLQ

Reputation: 15008

Convert long to "unsigned, 4 byte integer in network byte order" with ByteBuffer

The protocol I'm using requires sending back the current position in a file as a "unsigned, 4 byte integer in network byte order". There are several questions on this, but they are assuming I'm using Integers, not Longs

I am attempting to port this to NIO's ByteBuffer so it can be sent in the socket channel:

long bytesTransfered = ... some number of bytes transfered...
//TODO: What does this actually do?
outBuffer[0] = (byte) ((bytesTransfered >> 24) & 0xff);
outBuffer[1] = (byte) ((bytesTransfered >> 16) & 0xff);
outBuffer[2] = (byte) ((bytesTransfered >> 8) & 0xff);
//TODO: Why does netbeans say this does nothing?
outBuffer[3] = (byte) ((bytesTransfered >> 0) & 0xff);

Are their any methods in ByteBuffer that accomplish this? Hopefully in a more obvious, self-descriptive way then the bit-shifting magic above?

Upvotes: 1

Views: 6976

Answers (2)

parsifal
parsifal

Reputation: 646

Whether signed or unsigned, the bits are the same.

If you cast a long to an int, the JVM discards the high-order bits. The issue comes when promoting an int to a long: Java will sign-extend the value, filling in the high-order bits of the long with the most-significant bit of the int.

To resolve this problem, simply apply a mask to the long. The following should make this clear:

long value = Integer.MAX_VALUE + 1234L;
System.out.println("original value    = " + value);

int iValue = (int)value;
System.out.println("value as int      = " + iValue);
byte[] array = new byte[4];

ByteBuffer buf = ByteBuffer.wrap(array);
buf.putInt(0, iValue);

int iRetrieved = buf.getInt(0);
System.out.println("int from buf      = " + iRetrieved);

long retrieved = iRetrieved;
System.out.println("converted to long = " + retrieved);

retrieved = retrieved & 0xFFFFFFFFL;
System.out.println("high bytes masked = " + retrieved);

However, be aware that you still have only 32 bits. If the filesizes is greater than 4Gb you won't be able to fit it into 4 bytes (and if you have to worry about files > 2G, then you should worry about files > 4G).

Upvotes: 6

user207421
user207421

Reputation: 310913

That's exactly what ByteBuffer.putInt() is for. You say you're using long but you also only want to write four bytes, so you'll have to cast your long to int. Or else use putLong() and get 8 bytes.

Upvotes: 3

Related Questions