Reputation: 5651
I have a long
. I know this long
is not very big. It could be encoded as an unsigned integer into 7 bytes, actually.
I would like to write my long
into byte[7]
using ByteBuffer
and the little endian.
This
long myLong = ... //some value
byte[] myLongBytes = ByteBuffer.allocate(7).order(ByteOrder.LITTLE_ENDIAN).putLong(myLong).array();
throws IndexOutOfBoundsException
, of course. Can I even do this with ByteBuffer
? Should I do it in a different way?
Upvotes: 1
Views: 3686
Reputation: 8116
(Assuming little endian byte order as indicated in the OP)
(Assuming you want 56 least significant bits from the long being stored)
long myLong = someLongValue & 0x00FFFFFFFFFFFFFFL;
ByteBuffer bb = ByteBuffer.allocate(xxx).order(ByteOrder.LITTLE_ENDIAN);
bb.putLong(myLong);
bb.position(bb.position()-1);
for tail write (i.e. this long is the last write to the ByteBuffer
):
bb.putLong(myLong);
bb.limit(bb.position()-1);
Beware that this approach works only if you can ensure the ByteBuffer
capacity is large enough to fit this temporary extra byte.
Some example cases where this approach should be OK:
where this 56bit value is always followed by another field (then you are sure there is some capacity reserve)
when you are strictly using the ByteBuffer.limit()
feature and not (ab)using the ByteBuffer
for comfortable byte array writes (which is implied by your post)
bb.putInt((int)myLong);
bb.putShort((short)(myLong>>>32));
bb.put((byte)(myLong>>>48));
This works every time.
You might consider using byte array instead of long (depends on your use case).
Good luck!
Upvotes: 6
Reputation: 533472
You need to write a byte at a time such as (based on java.nio.Bits)
static private long makeLong(byte b6, byte b5, byte b4,
byte b3, byte b2, byte b1, byte b0)
{
return ((((long)b6 & 0xff) << 48) |
(((long)b5 & 0xff) << 40) |
(((long)b4 & 0xff) << 32) |
(((long)b3 & 0xff) << 24) |
(((long)b2 & 0xff) << 16) |
(((long)b1 & 0xff) << 8) |
(((long)b0 & 0xff) ));
}
static long getLongL(ByteBuffer bb, int bi) {
return makeLong(bb.get(bi + 6),
bb.get(bi + 5),
bb.get(bi + 4),
bb.get(bi + 3),
bb.get(bi + 2),
bb.get(bi + 1),
bb.get(bi ));
}
private static byte long6(long x) { return (byte)(x >> 48); }
private static byte long5(long x) { return (byte)(x >> 40); }
private static byte long4(long x) { return (byte)(x >> 32); }
private static byte long3(long x) { return (byte)(x >> 24); }
private static byte long2(long x) { return (byte)(x >> 16); }
private static byte long1(long x) { return (byte)(x >> 8); }
private static byte long0(long x) { return (byte)(x ); }
static void putLongL(ByteBuffer bb, int bi, long x) {
bb.put(bi + 6, long6(x));
bb.put(bi + 5, long5(x));
bb.put(bi + 4, long4(x));
bb.put(bi + 3, long3(x));
bb.put(bi + 2, long2(x));
bb.put(bi + 1, long1(x));
bb.put(bi , long0(x));
}
In general, I avoid making micro-optimisation like this as it adds complexity for little gain IMHO. If you want to save space I suggest using something like stop bit encoding which uses one byte for every 7 bits. i.e. a long might only use 1 byte for small values but could be much larger as required.
Upvotes: 5
Reputation: 21728
Java long
is the 64 bit so 64/8 = 8 byte value so you are not allocating enough space to it. Allocate 8 bytes, not seven.
Upvotes: -2
Reputation: 873
Do as below
byte[] myLongBytes = ByteBuffer.allocate(Long.SIZE / Byte.SIZE).putLong(myLong).array();
Upvotes: -2