Как мне преобразовать байт в длинный в Java?
Я читаю 8 байт данных с аппаратного устройства. Мне нужно преобразовать их в числовое значение. Я думаю, что я хочу преобразовать их в long, поскольку это должно соответствовать 8 байтов. Я не очень знаком с Java и операциями с типами данных низкого уровня. Кажется, у меня есть две проблемы (за исключением того, что документации для рассматриваемого оборудования почти нет). Байты ожидают, что они не будут подписаны, поэтому я не могу выполнить прямое целочисленное преобразование. Я не уверен, что они являются порядком байтов.
Любой совет будет принят во внимание.
Закончилось этим (взято из некоторого исходного кода, который я, вероятно, должен был прочитать неделю назад):
public static final long toLong (byte[] byteArray, int offset, int len)
{
long val = 0;
len = Math.min(len, 8);
for (int i = (len - 1); i >= 0; i--)
{
val <<= 8;
val |= (byteArray [offset + i] & 0x00FF);
}
return val;
}
11 ответов
Для порядка байтов проверьте с некоторыми числами, которые вы знаете, и тогда вы будете использовать сдвиг байтов, чтобы переместить их в длинный.
Вы можете найти это отправной точкой. http://www.janeg.ca/scjp/oper/shift.html
Сложность состоит в том, что в зависимости от порядка байтов будет меняться то, как вы это делаете, но вы будете сдвигаться на 24, 16, 8, а затем добавляете последний, в основном, если выполняете 32 бита, но вы идете дольше, так что просто сделайте дополнительное смещение.
Сдвиг байтов в соответствии с порядком байтов данных довольно прост. Есть маленькая хитрость с long
тип данных, однако, потому что бинарная операция на целочисленных типах int
или меньше продвигает операнды int
, Для сдвигов влево, превышающих 31 бит, это приведет к нулю, поскольку все биты были сдвинуты из int
спектр.
Итак, форсировать long
в том числе long
операнд в расчете. Ниже я делаю это, маскируя каждый байт значением 0xFFL, которое является long
, заставляя результат быть long
,
byte[] buf = new byte[8];
/* Fill buf somehow... */
long l = ((buf[0] & 0xFFL) << 56) |
((buf[1] & 0xFFL) << 48) |
((buf[2] & 0xFFL) << 40) |
((buf[3] & 0xFFL) << 32) |
((buf[4] & 0xFFL) << 24) |
((buf[5] & 0xFFL) << 16) |
((buf[6] & 0xFFL) << 8) |
((buf[7] & 0xFFL) << 0) ;
Байт #longValue() должен сделать это
А если нет (спасибо за исходный пример), вы можете использовать java.nio.ByteBuffer, например, в
public static long toLong(byte[] b) {
ByteBuffer bb = ByteBuffer.allocate(b.length);
bb.put(b);
return bb.getLong();
}
Первоначальный заказ BIG_ENDIAN, вы можете узнать больше здесь
ByteBuffer buffer = ByteBuffer.wrap(bytes);
buffer.getLong();
Я считаю, что вы могли бы извлечь выгоду из использования java.nio. Вот как вы можете хранить 8 байтов в длинном:
// Byte Array TO Long
public static long batol(byte[] buff) {
return batol(buff, false);
}
public static long batol(byte[] buff, boolean littleEndian) {
assert(buff.length == 8);
ByteBuffer bb = ByteBuffer.wrap(buff);
if (littleEndian) bb.order(ByteOrder.LITTLE_ENDIAN);
return bb.getLong();
}
Конечно, получающиеся длинные будут иметь подписанное представление, но они будут иметь идентичные двоичные значения с исходными данными. Для 64-битного + беззнакового и арифметического представления вам необходимо использовать BigInteger. Вот как конвертировать из "беззнаковых" данных, хранящихся в long, в правильный BigInteger:
// "Unsigned" Long TO Big Integer
public static BigInteger ultobi(long ul) {
byte[] buff = new byte[8];
ByteBuffer.wrap(buff).asLongBuffer().put(ul);
return new BigInteger(+1, buff);
}
Посмотрите на BigInteger(байт []). Это почти то, что вы хотите, за исключением того, что это подписанный. Таким образом, вы можете добавить еще один байт, прежде чем передать его в BigInteger.
Другое дело, что вы должны знать о порядке байтов.
Надеюсь это поможет.
Если вы читаете из InputStream
Вы также можете посмотреть на DataInputStream.readLong (). Java 1.5 представила Long.reverseBytes(long), который может помочь вам с порядком байтов.
public static long convertToLong(byte[] array)
{
ByteBuffer buffer = ByteBuffer.wrap(array);
return buffer.getLong();
}
Ты можешь использовать:
byte bVal = 127;
Long longVar = Long.valueOf(bVal);
Следующий код анализирует байты как число со знаком произвольной длины ≤ 8.
static long bytesToSignedNumber(boolean reverseOrder, byte... bytes) {
if (bytes.length > 8) bytes = Arrays.copyOfRange(bytes, 0, 8); //delete this line to ignore the higher excess bytes instead of the lower ones
int l = bytes.length;
long number = 0;
for (int i = 0; i < l; i++) {
long current;
if (l==3 || l==5 || l==6 || l==7 //delete this line if you want to operate with 3,5,6,7-byte signed numbers (unlikely)
|| !reverseOrder && (i > 0)
|| reverseOrder && (i < l-1)) {
current = ((long) bytes[i]) & 0x0000_0000_0000_00ff; //unsigned
} else {
current = (long) bytes[i]; //signed
}
if (reverseOrder) number += current << (8 * i);
else number = (number << 8) + current;
}
return number;
}
Он анализирует байтовый массив как число минимально существующего типа, преобразованное в long . Несколько примеров:
bytesToSignedNumber(false, 0x01, 0x04)
возвращается
260
(2 байт , как короткое замыкание )
bytesToSignedNumber(false, 0xF1, 0x04)
возвращается
-3836
(2 байт , как короткое замыкание )
bytesToSignedNumber(false, 0x01, 0x01, 0x04)
возвращается
65796
(3 байта как целое число )
bytesToSignedNumber(false, 0xF1, 0x01, 0x04)
возвращается
15794436
(3 байта как целое число )
bytesToSignedNumber(false, 0xF1, 0x01, 0x01, 0x04)
возвращается
-251592444
(4 байта как целое число )
bytesToSignedNumber(false, 0x0F, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04)
возвращается
1081146489369067777
(8 из 9 байт , как долго )
Другая альтернатива
От Google
com.google.common.primitives
Longs.fromByteArray(байты);