Come faccio a convertire Long in byte [] e viceversa in Java


159

Come faccio a convertire a longin byte[]e viceversa in Java?

Sto provando a convertire a in longin byte[]modo da poter inviare la byte[]connessione via TCP. Dall'altro lato voglio prenderlo byte[]e convertirlo nuovamente in a double.


Un'altra alternativa sarà Maps.transformValues, uno strumento generale per la conversione di raccolte. docs.guava-libraries.googlecode.com/git-history/release/javadoc/…
Raul,

1
Vedi anche stackoverflow.com/q/27559449/32453 se il tuo obiettivo è convertire un long nel minor numero di caratteri Base64.
rogerdpack,

Forse dovrebbe essere sottolineato che la pipeline di conversione è 'long -> byte [] -> double', non 'long -> byte [] -> long -> double'.
Kirill Gamazkov,

Risposte:


230
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();
}

O racchiuso in una classe per evitare di creare ripetutamente ByteBuffer:

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();
    }
}

Dato che questo sta diventando così popolare, voglio solo menzionare che penso che tu sia meglio usare una libreria come Guava nella stragrande maggioranza dei casi. E se hai una strana opposizione alle biblioteche, dovresti probabilmente considerare prima questa risposta per le soluzioni Java native. Penso che la cosa principale della mia risposta sia che non devi preoccuparti dell'endianità del sistema da solo.


3
Intelligente ... ma crei e scarti un ByteBuffer temporaneo per ogni conversione. Non va bene se si inviano più long per messaggio e / o molti messaggi.
Stephen C,

1
@Stephen - Stavo facendo abbastanza per dimostrare come utilizzare ByteBuffer, ma sono andato avanti e ho aggiunto un esempio di utilizzo in una classe di utilità.
Brad Mace,

8
Penso che il bytesToLong () qui fallirebbe poiché la posizione dopo il put è alla fine del buffer, non all'inizio. Penso che otterrai un'eccezione underflow buffer.
Alex Miller,

11
Pre-Java 8, è possibile utilizzare Long.SIZE / Byte.SIZE anziché Long.BYTES per evitare un numero magico.
jvdbogae,

8
Il riutilizzo di quel bytebuffer è altamente problematico, e non solo per i motivi di sicurezza dei thread, come altri hanno commentato. Non solo sarebbe necessario un '.clear ()' nel mezzo, ma ciò che non è ovvio è che chiamare .array () su ByteBuffer sta restituendo l'array di backup rispetto a una copia. Pertanto, se chiamate ripetutamente e trattenete gli altri risultati, in realtà sono tutti lo stesso array che ripetutamente sta sovrascrivendo i valori precedenti. Il link hadoop in un commento qui sotto è il più performante ed evita qualsiasi di questi problemi.
Aaron Zinman,


84

Ho testato il metodo ByteBuffer contro semplici operazioni bit a bit, ma quest'ultimo è significativamente più veloce.

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[] bytes, final int offset) {
    long result = 0;
    for (int i = offset; i < Long.BYTES + offset; i++) {
        result <<= Long.BYTES;
        result |= (bytes[i] & 0xFF);
    }
    return result;
}

1
Invece del risultato | = (b [i] & 0xFF); Potremmo semplicemente usare il risultato | = b [i]; come e con 0xFF per un po 'non modifica nulla.
Vipul,

3
@Vipul Il bit per bit e importa perché quando si fa solo result |= b[i]il valore del byte verrà prima convertito in long che significa estensione. Un byte con valore -128 (esadecimale 0x80) si trasformerà in un lungo con valore -128 (esadecimale 0xFFFF FFFF FFFF FF80). Primo dopo la conversione sono i valori o: ed insieme. Utilizzando bit a bit-e protegge contro questo convertendo prima il byte di un int e tagliare l'estensione del segno: (byte)0x80 & 0xFF ==> (int)0xFFFF FF80 & 0xFF ==> (int) 0x80. Perché i byte sono firmati in Java è un po 'un mistero per me, ma credo che sia adatto ad altri tipi.
Brainstorm

@Brainstorm Ho provato il caso -128 con | = b [i] e con | = (b [i] & 0xFF) e i risultati sono gli stessi !!
Mahmoud Hanafy,

Il problema è che il byte viene promosso prima che venga applicato lo shift, il che provoca strani problemi con il bit del segno. Quindi prima di tutto e (&) con 0xFF per ottenere il valore corretto da spostare.
Wytze,

Provo a convertire questi dati (data = new byte [] {(byte) 0xDB, (byte) 0xA7, 0x53, (byte) 0xF8, (byte) 0xA8, 0x0C, 0x66, 0x8};) in long, ma restituisce valore falso -2619032330856274424, il valore atteso è 989231983928329832
jefry jacky

29

Se stai cercando una versione veloce srotolata, questo dovrebbe fare il trucco, supponendo un array di byte chiamato "b" con una lunghezza di 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 [] come controparte esatta di quanto sopra

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)};

1
Grazie, il migliore!
Miha_x64,

15

Perché hai bisogno del byte []? perché non scriverlo semplicemente sul socket?

Presumo che tu intenda long piuttosto che Long , quest'ultimo deve consentire valori null.

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

DataInputStream dis = new DataInputStream(
     new BufferedInputStream(socket.getInputStream()));
long longValue = dis.readLong();

8
Ha chiesto come si converte in byte [] e viceversa. Buona risposta ma non ha risposto alla domanda. Ti chiedi perché, supponendo che non sia necessario, ma è un'ipotesi sbagliata. E se sta facendo cross-language o cross-platform? DataOutputStream non ti aiuterà lì.
user1132959,

4
Se sta eseguendo cross-language o cross-platform, è importante inviare i byte in un ordine noto. Questo metodo lo fa (li scrive prima "byte alto") secondo i documenti. La risposta accettata non lo fa (li scrive nell '"ordine corrente" secondo i documenti). La domanda afferma che vuole inviarli tramite una connessione TCP. Il byte[]è solo un mezzo a tal fine.
Ian McLaird,

3
@IanMcLaird La risposta accettata utilizza un ordine noto. Crea un nuovo ByteBufferche secondo i documenti "L'ordine iniziale di un buffer di byte è sempre BIG_ENDIAN.
David Phillips,

4

Basta scrivere il long in un DataOutputStream con un ByteArrayOutputStream sottostante . Da ByteArrayOutputStream è possibile ottenere l'array di byte tramite 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));       
        }
}

Funziona di conseguenza per altri primitivi.

Suggerimento: per TCP non è necessario il byte [] manualmente. Utilizzerai un socket socket e i suoi flussi

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

anziché.


4

È possibile utilizzare l'implementazione in org.apache.hadoop.hbase.util.Bytes http://hbase.apache.org/apidocs/org/apache/hadoop/hbase/util/Bytes.html

Il codice sorgente è qui:

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

Cerca i metodi toLong e toBytes.

Credo che la licenza del software ti consenta di prendere parti del codice e di usarlo, ma ti preghiamo di verificarlo.


Perché questa implementazione usa XOR (^ =) invece di OR? github.com/apache/hbase/blob/master/hbase-common/src/main/java/…
victtim

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;
    }

2
puoi saltare la ArrayList: byte statico pubblico [] longToBytes (long l) {long num = l; byte [] byte = nuovo byte [8]; for (int i = bytes.length - 1, i> = 0; i--) {byte [i] = (byte) (num & 0xff); num >> = 8; } ritorno bytesp; }
Verifica il

Il metodo originale non funziona con numeri negativi in ​​quanto viene inserito in un ciclo infinito mentre while (l! = 0), il metodo @ eckes non funziona con numeri oltre 127 perché non tiene conto dei byte che diventano negativi oltre 127 causa sono firmati.
Big_Bad_E

2

Aggiungerò un'altra risposta che è la più veloce possibile ׂ (sì, anche più della risposta accettata), MA non funzionerà per ogni singolo caso. TUTTAVIA, funzionerà per ogni scenario immaginabile:

Puoi semplicemente usare String come intermedio. Nota, questo ti darà il risultato corretto anche se sembra che l'utilizzo di String potrebbe produrre risultati errati FINO A QUANTO SAPI CHE STAI LAVORANDO CON STRINGHE "NORMALI". Questo è un metodo per aumentare l'efficacia e semplificare il codice che, in cambio, deve utilizzare alcune ipotesi sulle stringhe di dati su cui opera.

Contro dell'uso di questo metodo: se stai lavorando con alcuni caratteri ASCII come questi simboli all'inizio della tabella ASCII, le seguenti righe potrebbero non riuscire, ma ammettiamolo: probabilmente non li userai comunque.

Pro di utilizzare questo metodo: ricorda che la maggior parte delle persone di solito lavora con alcune stringhe normali senza caratteri insoliti e quindi il metodo è il modo più semplice e veloce per andare.

da Long a byte []:

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

da byte [] a Long:

long longVar = Long.valueOf(new String(byteArr)).longValue();

2
Ci scusiamo per il necropostaggio, ma è solo sbagliato. Per esempio. String.valueOf (0) .getBytes () [0] == 0x30. Sorpresa! String # getBytes restituirà i simboli delle cifre con codifica ASCII, non le cifre: '0'! = 0, ma '0' == 0x30
Kirill Gamazkov

Beh, forse se avessi letto la mia intera risposta, allora avresti visto che l'avevo avvertito nella risposta stessa ..
Yonatan Nir

1
Ah, ho perso il punto che i dati byte [] intermedi sono considerati (quasi) opachi. Il tuo trucco farà per questo scenario.
Kirill Gamazkov,

1

Se si sta già utilizzando un OutputStreamper scrivere nel socket, DataOutputStream potrebbe essere adatto. Ecco un esempio:

// Assumes you are currently working with a SocketOutputStream.

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

DataOutputStream dataOutputStream = new DataOutputStream(outputStream);

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

Ci sono metodi simili per short, int, float, ecc Si può quindi utilizzare DataInputStream sul lato ricevente.



0

Ecco un altro modo per convertire byte[]in longJava 8 o versioni successive:

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));
}

La conversione di a longpuò essere espressa come i bit di ordine superiore e inferiore di due valori interi soggetti a OR bit a bit. Nota che toUnsignedLongè della Integerclasse e la prima chiamata a toUnsignedLongpotrebbe essere superflua.

Anche la conversione opposta può essere srotolata, come altri hanno già detto.


0

Estensioni Kotlin per tipi Long e ByteArray:

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()
}

Puoi vedere il codice completo nella mia libreria https://github.com/ArtemBotnev/low-level-extensions

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.