在 Java 中我如何将 Long 类型转换为 byte[] 类型或者反过来

Java 中如何将long转换为byte[]或者反过来?

我正在尝试将long转换为byte[],以便能够通过TCP连接发送byte[]。另一方面,我想把byte[]转换回double

258125 次浏览
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();
}

或者包装在一个类中,以避免重复创建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();
}
}

由于这变得如此流行,我只想提一下,我认为在绝大多数情况下,您最好使用像Guava这样的库。如果你对库有一些奇怪的反对意见,你可能应该首先考虑这个答案作为本地java解决方案。我认为我的回答主要是为了让你自己不用担心系统的端点。

为什么需要字节[]?为什么不直接写入套接字呢?

我假设你的意思是而不是,后者需要允许空值。

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


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

如果你已经在使用OutputStream来写入套接字,那么DataOutputStream可能是一个很好的选择。这里有一个例子:

// Assumes you are currently working with a SocketOutputStream.


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


DataOutputStream dataOutputStream = new DataOutputStream(outputStream);


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

shortintfloat等也有类似的方法。然后你可以在接收端使用DataInputStream

只需要将long对象写入带有底层ByteArrayOutputStreamDataOutputStream。从ByteArrayOutputStream中,你可以通过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));
}
}

适用于其他原语。

提示:对于TCP,您不需要手动使用[]字节。您将使用套接字 socket及其流

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

代替。

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

你可以在org.apache.hadoop.hbase.util.Bytes http://hbase.apache.org/apidocs/org/apache/hadoop/hbase/util/Bytes.html中使用这个实现

源代码如下:

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

寻找toLong和toBytes方法。

我相信软件许可允许您获取部分代码并使用它,但请验证这一点。

你可以使用谷歌番石榴中的字节转换方法

例子:

byte[] bytes = Longs.toByteArray(12345L);

如果你正在寻找一个快速展开的版本,这应该可以做到,假设一个名为“b”的字节数组的长度为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[]作为上面的精确对应

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

我对ByteBuffer方法与普通的按位操作进行了测试,但后者要快得多。

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

对于Java 8+,我们可以使用添加的静态变量:

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

我会添加另一个可能是最快的答案ׂ(是的,甚至比公认的答案还要多),但它不会适用于每一种情况。然而,它将工作于每一个可以想象的场景:

您可以简单地使用String作为中间工具。注意,这将给你正确的结果,即使它看起来使用字符串可能会产生错误的结果,只要你知道你正在使用“正常”字符串。这是一种提高效率并使代码更简单的方法,作为回报,必须对它所操作的数据字符串使用一些假设。

使用这种方法的缺点:如果你正在处理一些ASCII字符,比如ASCII表开头的这些符号,下面的行可能会失败,但让我们面对它——你可能永远都不会使用它们。

使用这种方法的好处:记住,大多数人通常使用一些正常的字符串,没有任何不寻常的字符,然后这个方法是最简单和最快的方法。

从Long到byte[]:

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

从byte[]到Long:

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

下面是使用Java 8或更新版本将byte[]转换为long的另一种方法:

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

转换long可以表示为两个整数值的高阶位和低阶位,并进行位或运算。注意,toUnsignedLong来自Integer类,对toUnsignedLong的第一次调用可能是多余的。

正如其他人所提到的,相反的转换也可以展开。

Long和ByteArray类型的Kotlin扩展:

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

你可以在我的库https://github.com/ArtemBotnev/low-level-extensions中看到完整的代码

我发现这种方法是最友好的。

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


var l = new BigInteger(b);

在Java 9中,最好的方法是使用VarHandle,它将从字节数组中读取,就像它是一个长数组一样,因为性能使VarHandle实例成为一个静态final字段。

static final VarHandle HANDLE = MethodHandles.byteArrayViewVarHandle(Long.TYPE.arrayType(), ByteOrder.nativeOrder());


static long bytesToLong(byte[] bytes, int offset) {
return (long)HANDLE.get(bytes, offset);
}


static void longToBytes(byte[] bytes, int offset, long value) {
HANDLE.set(bytes, offset, value);
}
static byte[] longToBytes(Long l) {
return (l + "").getBytes(StandardCharsets.UTF_8);
}

目前所有的答案都比他们需要的更复杂,我不希望任何人在没有更简洁的选项的情况下找到这个线程。

您可以在一行中完成这两种转换。

字节[]to long:

ByteBuffer.wrap(yourBytes).getLong();

Long to byte[]:

ByteBuffer.wrap(new byte[8]).putLong(yourLong).array();
new ObjectMapper().writeValueAsString(1234L).getBytes(); //*
显然,就字节而言,这不是理想的解决方案,但现在似乎每个人都在这么做。 如果op想在另一端将其转换回double类型,则精度可能不是问题

(*如果不清楚,这表示:通过TCP作为JSON发送)

public static long ToInt64(byte[] buffer) throws OutOfRangeException {
if (buffer.length < 8) {
throw new OutOfRangeException();
}
long int64 = 0;
int64 = buffer[0] & 0xffL;
int64 |= ((long) buffer[1] << 8) & 0xff00L;
int64 |= ((long) buffer[2] << 16) & 0xff0000L;
int64 |= ((long) buffer[3] << 24) & 0xff000000L;
int64 |= ((long) buffer[4] << 32) & 0xff00000000L;
int64 |= ((long) buffer[5] << 40) & 0xff0000000000L;
int64 |= ((long) buffer[6] << 48) & 0xff000000000000L;
int64 |= ((long) buffer[7] << 56);
return int64;
}