简体   繁体   English

使用 ByteBuffer 将 n 字节数组转换为 integer

[英]Converting a n-bytes array to integer with ByteBuffer

I need to convert arbitrary sized byte arrays to a short / int / long .我需要将任意大小的字节 arrays 转换为short / int / long
This means I could receive 3 bytes to be converted to int :这意味着我可以接收3个字节来转换为int

final byte[] bytes = { 0b0000, 0b0000, 0b1111 }; // 15 - big endian
final int value = doConversion(bytes);

Thus, I'm trying to come up with a generic function.因此,我试图想出一个通用的 function。


ByteBuffer conversions works great when you have arrays of a size that exactly represent a short , int , long value.当 arrays 的大小恰好代表一个shortintlong值时, ByteBuffer转换效果很好。 But what if I have an int represented as a single byte?但是如果我有一个表示为单个字节的int呢?

final byte[] bytes = { 0b1111 }; // 15

It seems converting such a byte array to an int using a ByteBuffer requires resizing the array and padding it.似乎使用ByteBuffer将这样的字节数组转换为int需要调整数组的大小并填充它。
Things get even more complicated with a negative value, as the padding needs to be done with the most significant bit .负值会使事情变得更加复杂,因为填充需要使用最重要的位来完成。

final byte[] bytes = { (byte) 0b11110001 }; // -15 stored as two's complement

Is there an easier way to accomplish this task, or should I just use custom code?有没有更简单的方法来完成这项任务,或者我应该只使用自定义代码?
An example could be, in Kotlin, using extension functions:例如,在 Kotlin 中,使用扩展函数:

fun ByteArray.toShort(byteOrder: ByteOrder = LITTLE, signed: Boolean = true): Short =
    toInteger(Short.SIZE_BYTES, byteOrder, signed).toShort()

fun ByteArray.toInt(byteOrder: ByteOrder = LITTLE, signed: Boolean = true): Int =
    toInteger(Int.SIZE_BYTES, byteOrder, signed).toInt()

fun ByteArray.toLong(byteOrder: ByteOrder = LITTLE, signed: Boolean = true): Long =
    toInteger(Long.SIZE_BYTES, byteOrder, signed)

private fun ByteArray.toInteger(
     typeBytes: Int /* 2, 4, 8 */,
     byteOrder: ByteOrder /* little, big */, 
     signed: Boolean,
): Long {
    // Checks omitted...

    // If the byte array is bigger than the type bytes, it needs to be truncated
    val bytes =
        if (size > typeBytes) {
            if (byteOrder == LITTLE) {
                copyOf(typeBytes)
            } else {
                copyOfRange(size - typeBytes, size)
            }
        } else {
            copyOf()
        }

    val negative =
        signed && (this[if (byteOrder == LITTLE) bytes.size - 1 else 0]).toInt() and 0b1000000 != 0

    if (!negative) {
        return bytes.absoluteToLong(byteOrder)
    }

    // The number is stored as two's complement.
    // Thus we invert each byte and then sum 1 to obtain the absolute value
    for (i in bytes.indices) {
        bytes[i] = bytes[i].inv()
    }

    return -(bytes.absoluteToLong(byteOrder) + 1)
}

private fun ByteArray.absoluteToLong(byteOrder: ByteOrder): Long {
    var result = 0L
    var shift = 8 * (size - 1)
    val range =
        if (byteOrder == LITTLE) {
            size - 1 downTo 0
        } else {
            0 until size
        }

    for (i in range) {
        result = (this[i].toInt() and 0b11111111).toLong() shl shift or result
        shift -= 8
    }

    return result
}

The BigInteger class has a constructor that's convenient for this use case. BigInteger class 有一个方便此用例的构造函数。 Example:例子:

byte[] bytes = { 0b1111 }; 
int value = new BigInteger(bytes).intValue(); 

It does "sign-extension" for you: if the first byte value in the array is negative, the end result is negative.它为您执行“符号扩展”:如果数组中的第一个字节值为负,则最终结果为负。

It has also methods to retrieve the value as the other number types (short, long, ...).它还具有将值检索为其他数字类型(短、长、...)的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM