如何将字节数组转换为数字值(Java)?

99
我有一个包含8个字节的数组,我想将其转换为相应的数字值。
例如:
byte[] by = new byte[8];  // the byte array is stored in 'by'

// CONVERSION OPERATION
// return the numeric value

我希望有一个方法可以执行上述转换操作。


5
“numeric value”是什么意思?这些字节是否以二进制形式表示整数(long)或浮点数(double)?它们是数字的字符串表示形式吗?还是另一种表示形式? - starblue
1
这很有帮助:https://dev59.com/XW035IYBdhLWcg3weP7f - TacB0sS
注:TacB0sS的链接正是我真正需要的——可以进行正向和反向转换。 - Jay Taylor
new BigInteger(by).longValue() - user207421
9个回答

124

可以使用作为java.nio包一部分提供的Buffer来执行转换。

这里,源byte[]数组的长度为8,对应于一个long值的大小。

首先,将byte[]数组封装在ByteBuffer中,然后调用ByteBuffer.getLong方法获取long值:

ByteBuffer bb = ByteBuffer.wrap(new byte[] {0, 0, 0, 0, 0, 0, 0, 4});
long l = bb.getLong();

System.out.println(l);

结果

4

感谢dfa在评论中指出了ByteBuffer.getLong方法。


虽然它可能在这种情况下不适用,但Buffer的优美之处在于查看具有多个值的数组。

例如,如果我们有一个8字节的数组,并且我们想将其视为两个int值,我们可以使用ByteBuffer包装byte[]数组,将其视为IntBuffer并通过IntBuffer.get获得这些值:

ByteBuffer bb = ByteBuffer.wrap(new byte[] {0, 0, 0, 1, 0, 0, 0, 4});
IntBuffer ib = bb.asIntBuffer();
int i0 = ib.get(0);
int i1 = ib.get(1);

System.out.println(i0);
System.out.println(i1);

结果:

1
4

ByteBuffer.wrap(new byte[] {0, 0, 0, 1, 0, 0, 0, 4}).getLong()是什么意思?这个方法应该读取接下来的8个字节并将它们转换为一个长整型。 - dfa

114

假设第一个字节是最不重要的字节:

long value = 0;
for (int i = 0; i < by.length; i++)
{
   value += ((long) by[i] & 0xffL) << (8 * i);
}

如果第一个字节是最高有效位,则有些许不同:

long value = 0;
for (int i = 0; i < by.length; i++)
{
   value = (value << 8) + (by[i] & 0xff);
}

如果您需要使用的数字类型超过8个字节,请使用BigInteger 代替 long。

感谢 Aaron Digulla 纠正我的错误。


8
-1 字节是有符号值!并用移位运算(<<)替换 pow()!"value = (value << 8) + (by[i] & 0xff)" - Aaron Digulla
<< 移位运算符是否具有从右到左的优先级?上述代码是如何工作的?对我来说一切正常。只是想知道其运行原理。提前致谢。 - suraj
@Mnementh:移位运算符(<<)具有从右到左的优先级吗?上面的代码是如何工作的?对我来说一切都很好。只是想知道它的工作原理。提前致谢。 - suraj
5
如果有其他人遇到和我一样的问题,在第一个示例中,必须将 by[i] 转换为 long 类型,否则它仅适用于小于 2^32 的值。也就是说,value += ((long)by[i] & 0xffL) << (8 * i); - Luke

17

你可以使用或参考由谷歌提供的Guava库,该库提供了用于长整型和字节数组之间转换的实用方法。我的客户端代码:

    long content = 212000607777l;
    byte[] numberByte = Longs.toByteArray(content);
    logger.info(Longs.fromByteArray(numberByte));

https://google.github.io/guava/releases/21.0/api/docs/com/google/common/primitives/Longs.html - will.fiset

17

如果这是一个8字节的数字值,你可以尝试:

BigInteger n = new BigInteger(byteArray);

如果这是一个 UTF-8 字符缓冲区,那么您可以尝试:

BigInteger n = new BigInteger(new String(byteArray, "UTF-8"));

如果答案在第一个代码片段结束后就结束了,或者包含一些将字符串转换为“数字值”的代码,我会投票支持这个答案。现在,你的答案的后半部分似乎是一个无关紧要的附加说明。 - Laurence Gonsalves
我第一次的意思不是这个,我改变了我的答案。 - Vincent Robert

9

您也可以使用BigInteger来处理可变长度的字节。您可以将其转换为适合您需求的Long、Integer或Short。

new BigInteger(bytes).intValue();

或表示极性:
new BigInteger(1, bytes).intValue();

3

1

数组中的每个单元格都被视为无符号整数:

private int unsignedIntFromByteArray(byte[] bytes) {
int res = 0;
if (bytes == null)
    return res;


for (int i=0;i<bytes.length;i++){
    res = res | ((bytes[i] & 0xff) << i*8);
}
return res;
}

只是需要注意,我需要使用0xFFL,否则从int 0xFF到long的转换在我打印Long.toHexString(l)时会设置许多不正确的1位。 - Luke
你需要使用0xFFL,否则会得到符号扩展。 - Gray

0

您可以尝试使用此答案中的代码:https://dev59.com/dUnSa4cB1Zd3GeqPRtxs#68393576

它将字节解析为任意长度的有符号数字。以下是一些示例:

bytesToSignedNumber(false, 0xF1, 0x01, 0x04) 返回 15794436(3个字节作为int

bytesToSignedNumber(false, 0xF1, 0x01, 0x01, 0x04) 返回 -251592444(4个字节作为int

bytesToSignedNumber(false, 0xF1, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04) 返回 -1080581331768770303(8个字节中的9个字节作为long


0
public static long byteArrayToLong(byte[] bytes) {
    return ((long) (bytes[0]) << 56)
            + (((long) bytes[1] & 0xFF) << 48)
            + ((long) (bytes[2] & 0xFF) << 40)
            + ((long) (bytes[3] & 0xFF) << 32)
            + ((long) (bytes[4] & 0xFF) << 24)
            + ((bytes[5] & 0xFF) << 16)
            + ((bytes[6] & 0xFF) << 8)
            + (bytes[7] & 0xFF);
}

将字节数组(长整型为8个字节)转换为长整型。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接