使用 ByteBuffer 将 n 字节数组转换为整数
Converting a n-bytes array to integer with ByteBuffer
我需要将任意大小的字节数组转换为 short
/int
/long
.
这意味着我可以接收 3
字节以转换为 int
:
final byte[] bytes = { 0b0000, 0b0000, 0b1111 }; // 15 - big endian
final int value = doConversion(bytes);
因此,我正在尝试提出一个通用函数。
ByteBuffer
转换在您的数组大小正好代表 short
、int
、long
值时效果很好。但是,如果我有一个 int
表示为单个字节怎么办?
final byte[] bytes = { 0b1111 }; // 15
似乎使用 ByteBuffer
将这样的字节数组转换为 int
需要调整数组的大小并填充它。
对于负值,事情变得更加复杂,因为填充需要用 最高有效位 .
完成
final byte[] bytes = { (byte) 0b11110001 }; // -15 stored as two's complement
是否有更简单的方法来完成此任务,或者我应该只使用自定义代码?
例如,在 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
}
BigInteger class 有一个方便此用例的构造函数。示例:
byte[] bytes = { 0b1111 };
int value = new BigInteger(bytes).intValue();
它为您做“符号扩展”:如果数组中的第一个字节值为负,则最终结果为负。
它还有方法来检索其他数字类型(短、长、...)的值。
我需要将任意大小的字节数组转换为 short
/int
/long
.
这意味着我可以接收 3
字节以转换为 int
:
final byte[] bytes = { 0b0000, 0b0000, 0b1111 }; // 15 - big endian
final int value = doConversion(bytes);
因此,我正在尝试提出一个通用函数。
ByteBuffer
转换在您的数组大小正好代表 short
、int
、long
值时效果很好。但是,如果我有一个 int
表示为单个字节怎么办?
final byte[] bytes = { 0b1111 }; // 15
似乎使用 ByteBuffer
将这样的字节数组转换为 int
需要调整数组的大小并填充它。
对于负值,事情变得更加复杂,因为填充需要用 最高有效位 .
final byte[] bytes = { (byte) 0b11110001 }; // -15 stored as two's complement
是否有更简单的方法来完成此任务,或者我应该只使用自定义代码?
例如,在 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
}
BigInteger class 有一个方便此用例的构造函数。示例:
byte[] bytes = { 0b1111 };
int value = new BigInteger(bytes).intValue();
它为您做“符号扩展”:如果数组中的第一个字节值为负,则最终结果为负。
它还有方法来检索其他数字类型(短、长、...)的值。