Como converter um long
para um byte[]
e de volta em Java?
Estou tentando converter um long
para um byte[]
para poder enviar a byte[]
conexão TCP. Por outro lado, quero pegar isso byte[]
e convertê-lo novamente em um double
.
Como converter um long
para um byte[]
e de volta em Java?
Estou tentando converter um long
para um byte[]
para poder enviar a byte[]
conexão TCP. Por outro lado, quero pegar isso byte[]
e convertê-lo novamente em um double
.
Respostas:
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.
Você pode usar os métodos de conversão de bytes do Google Guava .
Exemplo:
byte[] bytes = Longs.toByteArray(12345L);
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;
}
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.
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)};
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();
byte[]
é apenas um meio para esse fim.
ByteBuffer
que, de acordo com os documentos "A ordem inicial de um buffer de bytes é sempre BIG_ENDIAN."
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.
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:
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.
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;
}
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();
Se você já estiver usando um OutputStream
para 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.
Com ByteBuffer.allocate (8) .putLong (obj) .array ():
public byte[] toBytes(Long obj) {
if (obj != null) {
return ByteBuffer.allocate(8).putLong(obj).array();
return null;
}
Fonte:
Para muitos outros exemplos de uso do ByteBuffer:
Aqui está outra maneira de converter byte[]
para o long
uso 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 long
pode 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 Integer
classe e a primeira chamada para toUnsignedLong
pode ser supérflua.
A conversão oposta também pode ser desenrolada, como outros mencionaram.
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