Как мне преобразовать байт в длинный в 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(байты);

Другие вопросы по тегам