177

How do I convert a long to a byte[] and back in Java?

I'm trying convert a long to a byte[] so that I will be able to send the byte[] over a TCP connection. On the other side I want to take that byte[] and convert it back into a double.

Dave Jarvis
  • 28,853
  • 37
  • 164
  • 291
Emre801
  • 2,615
  • 5
  • 22
  • 28
  • 1
    Another alternative will be Maps.transformValues, a general tooling for converting collections. http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/Maps.html – Raul Dec 18 '12 at 16:29
  • 1
    See also http://stackoverflow.com/q/27559449/32453 if your goal is to convert a long into the fewest number of Base64 chars. – rogerdpack May 30 '16 at 20:19
  • 1
    Maybe it should be emphasized that the conversion pipeline is 'long -> byte[] -> double', not 'long -> byte[] -> long -> double'. – Kirill Gamazkov Mar 17 '17 at 11:14

13 Answers13

251
public byte[] longToBytes(long x) {
    ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
    buffer.putLong(x);
    return buffer.array();
}

public long bytesToLong(byte[] bytes) {
    ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
    buffer.put(bytes);
    buffer.flip();//need flip 
    return buffer.getLong();
}

Or wrapped in a class to avoid repeatedly creating ByteBuffers:

public class ByteUtils {
    private static ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);    

    public static byte[] longToBytes(long x) {
        buffer.putLong(0, x);
        return buffer.array();
    }

    public static long bytesToLong(byte[] bytes) {
        buffer.put(bytes, 0, bytes.length);
        buffer.flip();//need flip 
        return buffer.getLong();
    }
}

Since this is getting so popular, I just want to mention that I think you're better off using a library like Guava in the vast majority of cases. And if you have some strange opposition to libraries, you should probably consider this answer first for native java solutions. I think the main thing my answer really has going for it is that you don't have to worry about the endian-ness of the system yourself.

Community
  • 1
  • 1
Brad Mace
  • 26,280
  • 15
  • 94
  • 141
  • 3
    Clever ... but you create and discard a temporary ByteBuffer for each conversion. Not good if you are sending multiple longs per message and/or lots of messages. – Stephen C Dec 19 '10 at 23:28
  • 1
    @Stephen - I was just doing enough to demonstrate how to use ByteBuffer, but I went ahead and added an example of using it in a utility class. – Brad Mace Dec 19 '10 at 23:31
  • 9
    I think the bytesToLong() here would fail as the position after the put is at the end of the buffer, not the beginning. I think you'd get a buffer underflow exception. – Alex Miller Sep 01 '11 at 13:56
  • 1
    @BradMace, can you please edit your answer, this answer is wrong per Alex Miller, and using your method [static long bytesToLong(bytes)] I run into troubles.. You should have put bytes in proper location or you should clear buffer. I was getting BufferOverflowException. – nullptr Dec 18 '12 at 05:29
  • 1
    Great answer. It wasn't immediately clear to me why you need to "flip", but I stumbled upon this article which helped a lot! http://tutorials.jenkov.com/java-nio/buffers.html Perhaps flip is a misnomer? – Reinstate Monica 2331977 Nov 01 '13 at 12:54
  • 12
    Pre-Java 8, you can use Long.SIZE/Byte.SIZE instead of Long.BYTES to avoid a magic number. – jvdbogae Jul 16 '14 at 10:58
  • 12
    The reuse of that bytebuffer is highly problematic, and not just for the thread-safety reasons as others commented. Not only would a '.clear()' be needed in between, but what's not obvious is that calling .array() on the ByteBuffer is returning the backing array versus a copy. Thus if you call repeatedly and hold onto the other results, they're actually all the same array that repeatedly is overwriting the previous values. The hadoop link in a comment below is the most performant and avoids any of these issues. – Aaron Zinman Nov 05 '14 at 00:15
  • Anyone else only getting java.nio.BufferOverflowException issues? – Snipe3000 Apr 08 '21 at 22:16
96

You could use the Byte conversion methods from Google Guava.

Example:

byte[] bytes = Longs.toByteArray(12345L);
Sonson123
  • 9,321
  • 10
  • 46
  • 68
89

I tested the ByteBuffer method against plain bitwise operations but the latter is significantly faster.

public static byte[] longToBytes(long l) {
    byte[] result = new byte[8];
    for (int i = 7; i >= 0; i--) {
        result[i] = (byte)(l & 0xFF);
        l >>= 8;
    }
    return result;
}

public static long bytesToLong(final byte[] b) {
    long result = 0;
    for (int i = 0; i < 8; i++) {
        result <<= 8;
        result |= (b[i] & 0xFF);
    }
    return result;
}

For Java 8+ we can use the static variables that were added:

public static byte[] longToBytes(long l) {
    byte[] result = new byte[Long.BYTES];
    for (int i = Long.BYTES - 1; i >= 0; i--) {
        result[i] = (byte)(l & 0xFF);
        l >>= Byte.SIZE;
    }
    return result;
}

public static long bytesToLong(final byte[] b) {
    long result = 0;
    for (int i = 0; i < Long.BYTES; i++) {
        result <<= Byte.SIZE;
        result |= (b[i] & 0xFF);
    }
    return result;
}
Wytze
  • 1,342
  • 10
  • 15
  • 1
    Instead of result |= (b[i] & 0xFF); We could simply use result |= b[i]; as and with 0xFF for a bit doesnt modify anything. – Vipul Aug 03 '15 at 09:58
  • 4
    @Vipul The bitwise-and does matter because when doing just `result |= b[i]` the byte value will first be converted to long which does sign extension. A byte with value -128 (hex `0x80`) will turn into a long with value -128 (hex `0xFFFF FFFF FFFF FF80`). First after the conversion are the values or:ed together. Using bitwise-and protects against this by first converting the byte to an int and cutting off the sign extension: `(byte)0x80 & 0xFF ==> (int)0xFFFF FF80 & 0xFF ==> (int) 0x80`. Why bytes are signed in java is a bit of a mystery to me, but I guess that it's to fit in with other types. – Brainstorm Aug 26 '15 at 08:25
  • @Brainstorm I tried case -128 with |= b[i] and with |= (b[i] & 0xFF) and the results are the same !! – Mahmoud Hanafy Feb 28 '16 at 12:44
  • The problem is that the byte gets promoted before the shift is applied which causes strange problems with the sign bit. Therefore we first and (&) it with 0xFF to get the correct value to shift. – Wytze Feb 29 '16 at 13:46
  • I try to convert this data (data = new byte[]{(byte) 0xDB, (byte) 0xA7, 0x53, (byte) 0xF8, (byte) 0xA8, 0x0C, 0x66, 0x8}; ) to long, but it return false value -2619032330856274424, the expected value is 989231983928329832 – jefry jacky Jul 28 '17 at 06:57
  • The hexadecimal representation of 989231983928329832 is 0DBA753F8A80C668. The leading 0 probably fell of causing the conversion error. – Wytze Jul 29 '17 at 14:09
  • this is the same as from google guava. at least the first. it should be safe. – mmm Sep 21 '20 at 09:40
  • The left-shift by `Long.BYTES` is wrong. It does not communicate the intent. It only works by coincidece: `Long.BYTES` is 8. Replace this with Integer, and it will be wrong. Instead, left-shift by `Byte.SIZE`. – Christian Hujer Dec 04 '20 at 06:26
  • My original answer was edited by someone. I have restored it as it was. – Wytze Dec 05 '20 at 14:09
40

If you are looking for a fast unrolled version, this should do the trick, assuming a byte array called "b" with a length of 8:

byte[] -> long

long l = ((long) b[7] << 56)
       | ((long) b[6] & 0xff) << 48
       | ((long) b[5] & 0xff) << 40
       | ((long) b[4] & 0xff) << 32
       | ((long) b[3] & 0xff) << 24
       | ((long) b[2] & 0xff) << 16
       | ((long) b[1] & 0xff) << 8
       | ((long) b[0] & 0xff);

long -> byte[] as an exact counterpart to the above

byte[] b = new byte[] {
       (byte) lng,
       (byte) (lng >> 8),
       (byte) (lng >> 16),
       (byte) (lng >> 24),
       (byte) (lng >> 32),
       (byte) (lng >> 40),
       (byte) (lng >> 48),
       (byte) (lng >> 56)};
Michael Böckling
  • 6,286
  • 6
  • 46
  • 59
15

Why do you need the byte[]? why not just write it to the socket?

I assume you mean long rather than Long, the latter needs to allow for null values.

DataOutputStream dos = new DataOutputStream(
     new BufferedOutputStream(socket.getOutputStream()));
dos.writeLong(longValue);

DataInputStream dis = new DataInputStream(
     new BufferedInputStream(socket.getInputStream()));
long longValue = dis.readLong();
Evan Knowles
  • 7,097
  • 2
  • 32
  • 67
Peter Lawrey
  • 498,481
  • 72
  • 700
  • 1,075
  • 8
    He asked how you convert to byte[] and back. Good answer but didn't answer the question. You ask why because you assume it is unnecessary but that's a wrong assumption. What if he is doing cross-language or cross-platform? DataOutputStream won't help you there. – user1132959 May 12 '13 at 19:05
  • 4
    If he's doing cross-language or cross-platform, then sending the bytes in a known order is important. This method does that (it writes them "high byte first") according to the docs. The accepted answer does not (it writes them in the "current order" according to the docs). The question states that he wants to send them over a TCP connection. The `byte[]` is just a means to that end. – Ian McLaird Aug 16 '13 at 19:27
  • 3
    @IanMcLaird The accepted answer does use a known order. It creates a new `ByteBuffer` which according to the docs _"The initial order of a byte buffer is always BIG_ENDIAN._ – David Phillips May 25 '16 at 22:55
4

You could use the implementation in org.apache.hadoop.hbase.util.Bytes http://hbase.apache.org/apidocs/org/apache/hadoop/hbase/util/Bytes.html

The source code is here:

http://grepcode.com/file/repository.cloudera.com/content/repositories/releases/com.cloudera.hbase/hbase/0.89.20100924-28/org/apache/hadoop/hbase/util/Bytes.java#Bytes.toBytes%28long%29

Look for the toLong and toBytes methods.

I believe the software license allows you to take parts of the code and use it but please verify that.

Marquez
  • 5,268
  • 3
  • 26
  • 37
  • Why does that implementation use XOR (^=) instead of OR? https://github.com/apache/hbase/blob/master/hbase-common/src/main/java/org/apache/hadoop/hbase/util/Bytes.java – victtim Aug 27 '18 at 22:39
4

Just write the long to a DataOutputStream with an underlying ByteArrayOutputStream. From the ByteArrayOutputStream you can get the byte-array via toByteArray():

class Main
{

        public static byte[] long2byte(long l) throws IOException
        {
        ByteArrayOutputStream baos=new ByteArrayOutputStream(Long.SIZE/8);
        DataOutputStream dos=new DataOutputStream(baos);
        dos.writeLong(l);
        byte[] result=baos.toByteArray();
        dos.close();    
        return result;
        }


        public static long byte2long(byte[] b) throws IOException
        {
        ByteArrayInputStream baos=new ByteArrayInputStream(b);
        DataInputStream dos=new DataInputStream(baos);
        long result=dos.readLong();
        dos.close();
        return result;
        }


        public static void main (String[] args) throws java.lang.Exception
        {

         long l=123456L;
         byte[] b=long2byte(l);
         System.out.println(l+": "+byte2long(b));       
        }
}

Works for other primitives accordingly.

Hint: For TCP you do not need the byte[] manually. You will use a Socket socket and its streams

OutputStream os=socket.getOutputStream(); 
DataOutputStream dos=new DataOutputStream(os);
dos.writeLong(l);
//etc ..

instead.

Michael Konietzka
  • 5,183
  • 2
  • 24
  • 29
4

I find this method to be most friendly.

var b = BigInteger.valueOf(x).toByteArray();

var l = new BigInteger(b);
HexllioN
  • 41
  • 1
  • 2
3
 public static long bytesToLong(byte[] bytes) {
        if (bytes.length > 8) {
            throw new IllegalMethodParameterException("byte should not be more than 8 bytes");

        }
        long r = 0;
        for (int i = 0; i < bytes.length; i++) {
            r = r << 8;
            r += bytes[i];
        }

        return r;
    }



public static byte[] longToBytes(long l) {
        ArrayList<Byte> bytes = new ArrayList<Byte>();
        while (l != 0) {
            bytes.add((byte) (l % (0xff + 1)));
            l = l >> 8;
        }
        byte[] bytesp = new byte[bytes.size()];
        for (int i = bytes.size() - 1, j = 0; i >= 0; i--, j++) {
            bytesp[j] = bytes.get(i);
        }
        return bytesp;
    }
maziar
  • 511
  • 3
  • 9
  • 2
    you can skip the ArrayList: public static byte[] longToBytes(long l) { long num = l; byte[] bytes = new byte[8]; for (int i = bytes.length - 1, i >= 0; i--) { bytes[i] = (byte)(num & 0xff); num >>= 8; } return bytesp; } – eckes Nov 16 '13 at 16:05
  • The original method doesn't work with negative numbers as it gets in an infinite loop in while (l != 0), @eckes's method doesn't work with numbers over 127 because he doesn't account for bytes going negative over 127 cause they are signed. – Big_Bad_E May 18 '19 at 15:11
2

I will add another answer which is the fastest one possible ׂ(yes, even more than the accepted answer), BUT it will not work for every single case. HOWEVER, it WILL work for every conceivable scenario:

You can simply use String as intermediate. Note, this WILL give you the correct result even though it seems like using String might yield the wrong results AS LONG AS YOU KNOW YOU'RE WORKING WITH "NORMAL" STRINGS. This is a method to increase effectiveness and make the code simpler which in return must use some assumptions on the data strings it operates on.

Con of using this method: If you're working with some ASCII characters like these symbols in the beginning of the ASCII table, the following lines might fail, but let's face it - you probably will never use them anyway.

Pro of using this method: Remember that most people usually work with some normal strings without any unusual characters and then the method is the simplest and fastest way to go.

from Long to byte[]:

byte[] arr = String.valueOf(longVar).getBytes();

from byte[] to Long:

long longVar = Long.valueOf(new String(byteArr)).longValue();
Yonatan Nir
  • 8,303
  • 23
  • 80
  • 156
  • 2
    Sorry for necroposting, but that's just wrong. E. g. String.valueOf(0).getBytes()[0] == 0x30. Surprise! String#getBytes will return ASCII-encoded digit symbols, not digits: '0' != 0, but '0' == 0x30 – Kirill Gamazkov Mar 11 '17 at 17:07
  • Well maybe if you had read my entire answer then you'd seen I have warned about it in the answer itself.. – Yonatan Nir Mar 12 '17 at 07:50
  • 1
    Ah, I missed the point that intermediate byte[] data is treated as (almost) opaque. Your trick will do for this scenario. – Kirill Gamazkov Mar 17 '17 at 11:16
1

Kotlin extensions for Long and ByteArray types:

fun Long.toByteArray() = numberToByteArray(Long.SIZE_BYTES) { putLong(this@toByteArray) }

private inline fun numberToByteArray(size: Int, bufferFun: ByteBuffer.() -> ByteBuffer): ByteArray =
    ByteBuffer.allocate(size).bufferFun().array()

@Throws(NumberFormatException::class)
fun ByteArray.toLong(): Long = toNumeric(Long.SIZE_BYTES) { long }

@Throws(NumberFormatException::class)
private inline fun <reified T: Number> ByteArray.toNumeric(size: Int, bufferFun: ByteBuffer.() -> T): T {
    if (this.size != size) throw NumberFormatException("${T::class.java.simpleName} value must contains $size bytes")

    return ByteBuffer.wrap(this).bufferFun()
}

You can see full code in my library https://github.com/ArtemBotnev/low-level-extensions

Artem Botnev
  • 1,370
  • 1
  • 9
  • 15
0

If you are already using an OutputStream to write to the socket, then DataOutputStream might be a good fit. Here is an example:

// Assumes you are currently working with a SocketOutputStream.

SocketOutputStream outputStream = ...
long longValue = ...

DataOutputStream dataOutputStream = new DataOutputStream(outputStream);

dataOutputStream.writeLong(longValue);
dataOutputStream.flush();

There are similar methods for short, int, float, etc. You can then use DataInputStream on the receiving side.

Matt Solnit
  • 28,352
  • 8
  • 50
  • 56
0

Here's another way to convert byte[] to long using Java 8 or newer:

private static int bytesToInt(final byte[] bytes, final int offset) {
    assert offset + Integer.BYTES <= bytes.length;

    return (bytes[offset + Integer.BYTES - 1] & 0xFF) |
            (bytes[offset + Integer.BYTES - 2] & 0xFF) << Byte.SIZE |
            (bytes[offset + Integer.BYTES - 3] & 0xFF) << Byte.SIZE * 2 |
            (bytes[offset + Integer.BYTES - 4] & 0xFF) << Byte.SIZE * 3;
}

private static long bytesToLong(final byte[] bytes, final int offset) {
    return toUnsignedLong(bytesToInt(bytes, offset)) << Integer.SIZE |
            toUnsignedLong(bytesToInt(bytes, offset + Integer.BYTES));
}

Converting a long can be expressed as the high- and low-order bits of two integer values subject to a bitwise-OR. Note that the toUnsignedLong is from the Integer class and the first call to toUnsignedLong may be superfluous.

The opposite conversion can be unrolled as well, as others have mentioned.

Dave Jarvis
  • 28,853
  • 37
  • 164
  • 291