Como faço para converter Long em byte [] e voltar em java

159

Como converter um longpara um byte[]e de volta em Java?

Estou tentando converter um longpara um byte[]para poder enviar a byte[]conexão TCP. Por outro lado, quero pegar isso byte[]e convertê-lo novamente em um double.

Emre801
fonte
Outra alternativa será o Maps.transformValues, uma ferramenta geral para converter coleções. docs.guava-libraries.googlecode.com/git-history/release/javadoc/…
Raul
1
Consulte também stackoverflow.com/q/27559449/32453 se seu objetivo é converter um número longo no menor número de caracteres Base64.
Rogerdpack # 30/16
Talvez seja necessário enfatizar que o pipeline de conversão é 'longo -> byte [] -> duplo', não 'longo -> byte [] -> longo -> duplo'.
Kirill Gamazkov 17/03/19

Respostas:

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

Ou agrupado em uma classe para evitar a criação repetida de 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();
    }
}

Como isso está ficando tão popular, só quero mencionar que acho melhor você usar uma biblioteca como o Guava na grande maioria dos casos. E se você tiver alguma oposição estranha às bibliotecas, provavelmente considere esta resposta primeiro para soluções java nativas. Eu acho que a principal coisa que minha resposta realmente tem a oferecer é que você não precisa se preocupar com a continuidade do sistema.

Brad Mace
fonte
3
Inteligente ... mas você cria e descarta um ByteBuffer temporário para cada conversão. Não é bom se você estiver enviando vários longos por mensagem e / ou muitas mensagens.
Stephen C
1
@ Stephen - Eu estava apenas fazendo o suficiente para demonstrar como usar o ByteBuffer, mas fui adiante e adicionei um exemplo de uso em uma classe de utilitário.
Brad Mace
8
Eu acho que os bytesToLong () aqui falhariam, pois a posição após o put está no final do buffer, não no começo. Eu acho que você receberia uma exceção de buffer insuficiente.
Alex Miller
11
Antes do Java 8, você pode usar Long.SIZE / Byte.SIZE em vez de Long.BYTES para evitar um número mágico.
jvdbogae
8
A reutilização desse bytebuffer é altamente problemática, e não apenas pelos motivos de segurança do encadeamento, como outros comentaram. Não seria necessário apenas um '.clear ()' no meio, mas o que não é óbvio é que a chamada .array () no ByteBuffer está retornando a matriz de backup versus uma cópia. Portanto, se você ligar repetidamente e se apegar aos outros resultados, eles serão todos da mesma matriz que repetidamente substituirá os valores anteriores. O link hadoop em um comentário abaixo é o de maior desempenho e evita qualquer um desses problemas.
Aaron Zinman #
84

Testei o método ByteBuffer em operações simples de bit a bit, mas o último é significativamente mais rápido.

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;
}
Wytze
fonte
1
Em vez de resultado | = (b [i] & 0xFF); Nós poderíamos simplesmente usar o resultado | = b [i]; como e com 0xFF por um tempo não modifica nada.
Vipul
3
@Vipul O bit a bit - e importa, porque ao fazer apenas result |= b[i]o valor do byte será primeiro convertido em longo, o que significa extensão de sinal. Um byte com o valor -128 (hex 0x80) se tornará longo com o valor -128 (hex 0xFFFF FFFF FFFF FF80). Primeiro após a conversão estão os valores ou: ed juntos. Usando bit a bit e protege contra esta convertendo primeiro o byte para um int e cortando a extensão de sinal: (byte)0x80 & 0xFF ==> (int)0xFFFF FF80 & 0xFF ==> (int) 0x80. Por que bytes são assinados em java é um mistério para mim, mas acho que é para se encaixar em outros tipos.
Brainstorm
@ Brainstorm Tentei o caso -128 com | = b [i] e | | (b [i] & 0xFF) e os resultados são os mesmos !!
Mahmoud Hanafy
O problema é que o byte é promovido antes da mudança ser aplicada, o que causa problemas estranhos no bit de sinal. Portanto, primeiro e (&) com 0xFF para obter o valor correto para mudar.
Wytze
Eu tento converter esses dados (data = novo byte [] {(byte) 0xDB, (byte) 0xA7, 0x53, (byte) 0xF8, (byte) 0xA8, 0x0C, 0x66, 0x8};) para longo, mas ele retorna valor falso -2619032330856274424, o valor esperado é 989231983928329832
jefry jacky
29

Se você está procurando uma versão rápida desenrolada, isso deve ser suficiente, assumindo uma matriz de bytes chamada "b" com um comprimento de 8:

byte [] -> longo

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 [] como uma contraparte exata dos itens acima

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
fonte
1
Obrigado, o melhor!
Miha_x64
15

Por que você precisa do byte []? por que não escrevê-lo no soquete?

Suponho que você queira dizer longo e não longo , o último precisa permitir valores nulos.

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

DataInputStream dis = new DataInputStream(
     new BufferedInputStream(socket.getInputStream()));
long longValue = dis.readLong();
Peter Lawrey
fonte
8
Ele perguntou como você converte em byte [] e vice-versa. Boa resposta, mas não respondeu à pergunta. Você pergunta porque, porque supõe que é desnecessário, mas isso é uma suposição errada. E se ele estiver fazendo cross-language ou multiplataforma? O DataOutputStream não o ajudará lá.
User1132959
4
Se ele estiver usando vários idiomas ou várias plataformas, é importante enviar os bytes em uma ordem conhecida. Esse método faz isso (ele os grava "primeiro em bytes altos"), de acordo com os documentos. A resposta aceita não (ela as escreve na "ordem atual" de acordo com os documentos). A pergunta afirma que ele deseja enviá-los por uma conexão TCP. O byte[]é apenas um meio para esse fim.
22613 Ian McLaird
3
@IanMcLaird A resposta aceita usa um pedido conhecido. Ele cria um novo ByteBufferque, de acordo com os documentos "A ordem inicial de um buffer de bytes é sempre BIG_ENDIAN."
David Phillips
4

Basta gravar o comprimento em um DataOutputStream com um ByteArrayOutputStream subjacente . No ByteArrayOutputStream, você pode obter a matriz de bytes 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));       
        }
}

Funciona para outros primitivos de acordo.

Dica: para o TCP, você não precisa do byte [] manualmente. Você usará um soquete socket e seus fluxos

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

em vez de.

Michael Konietzka
fonte
4

Você pode usar a implementação em org.apache.hadoop.hbase.util.Bytes http://hbase.apache.org/apidocs/org/apache/hadoop/hbase/util/Bytes.html

O código fonte está aqui:

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

Procure os métodos toLong e toBytes.

Acredito que a licença do software permita que você pegue partes do código e o use, mas verifique isso.

Marquez
fonte
Por que essa implementação usa XOR (^ =) em vez de 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;
    }
maziar
fonte
2
você pode pular o ArrayList: byte estático público [] longToBytes (long l) {long num = l; byte [] bytes = novo byte [8]; for (int i = bytes.length - 1, i> = 0; i--) {bytes [i] = (byte) (num & 0xff); num >> = 8; } retornar bytesp; }
eckes 16/11/2013
O método original não funciona com números negativos, pois entra em um loop infinito enquanto (l! = 0), o método de @eckes não funciona com números acima de 127 porque ele não considera bytes negativos com 127 eles são assinados.
Big_Bad_E
2

Adicionarei outra resposta que seja a mais rápida possível ׂ (sim, até mais do que a resposta aceita), mas não funcionará em todos os casos. No entanto, funcionará para todos os cenários possíveis:

Você pode simplesmente usar String como intermediário. Observe que isso fornecerá o resultado correto, mesmo que pareça que o uso de String possa produzir resultados errados, desde que você saiba que está trabalhando com seqüências de caracteres "normais". Este é um método para aumentar a eficácia e tornar o código mais simples, que por sua vez deve usar algumas suposições nas cadeias de dados em que opera.

Para usar este método: Se você estiver trabalhando com alguns caracteres ASCII como esses símbolos no início da tabela ASCII, as seguintes linhas podem falhar, mas vamos ser sinceros - você provavelmente nunca os usará de qualquer maneira.

Profissional do uso desse método: lembre - se de que a maioria das pessoas geralmente trabalha com algumas seqüências normais, sem caracteres incomuns, e o método é o caminho mais simples e rápido.

de Longa para byte []:

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

de byte [] a Long:

long longVar = Long.valueOf(new String(byteArr)).longValue();
Yonatan Nir
fonte
2
Desculpe pelo necroposting, mas isso é errado. Por exemplo. String.valueOf (0) .getBytes () [0] == 0x30. Surpresa! A sequência de caracteres # getBytes retornará símbolos de dígitos codificados em ASCII, não dígitos: '0'! = 0, mas '0' == 0x30
Kirill Gamazkov
Bem, talvez se você tivesse lido a minha resposta inteira, então você tinha visto eu ter avisado sobre isso no próprio .. resposta
Yonatan Nir
1
Ah, eu perdi o ponto em que dados de bytes intermediários [] são tratados como (quase) opacos. Seu truque servirá para esse cenário.
Kirill Gamazkov 17/03/19
1

Se você já estiver usando um OutputStreampara gravar no soquete, o DataOutputStream pode ser uma boa opção. Aqui está um exemplo:

// Assumes you are currently working with a SocketOutputStream.

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

DataOutputStream dataOutputStream = new DataOutputStream(outputStream);

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

Existem métodos semelhantes para short, int, float, etc. Você pode então usar DataInputStream no lado receptor.

Matt Solnit
fonte
0

Aqui está outra maneira de converter byte[]para o longuso do Java 8 ou mais recente:

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

A conversão de a longpode ser expressa como os bits de ordem alta e baixa de dois valores inteiros sujeitos a um OR bit a bit. Observe que o toUnsignedLongé da Integerclasse e a primeira chamada para toUnsignedLongpode ser supérflua.

A conversão oposta também pode ser desenrolada, como outros mencionaram.

Dave Jarvis
fonte
0

Extensões Kotlin para os tipos 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()
}

Você pode ver o código completo em minha biblioteca https://github.com/ArtemBotnev/low-level-extensions

Artem Botnev
fonte